The userspace interface of the kernel crypto API is documented with
 * a general explanation
 * a discussion of the memory in-place operation
 * the description of the message digest API
 * the description of the symmetric cipher API

In addition, a fully self contained example that can readily be used as
a library is added as well.

Signed-off-by: Stephan Mueller <smuel...@chronox.de>
CC: Marek Vasut <ma...@denx.de>
---
 Documentation/crypto/crypto-API-userspace.txt | 662 ++++++++++++++++++++++++++
 1 file changed, 662 insertions(+)
 create mode 100644 Documentation/crypto/crypto-API-userspace.txt

diff --git a/Documentation/crypto/crypto-API-userspace.txt 
b/Documentation/crypto/crypto-API-userspace.txt
new file mode 100644
index 0000000..30ca6a7
--- /dev/null
+++ b/Documentation/crypto/crypto-API-userspace.txt
@@ -0,0 +1,662 @@
+Introduction
+============
+
+The concepts of the kernel crypto API visible to kernel space is fully
+applicable to the user space interface as well. Therefore, the kernel crypto 
API
+high level discussion for the in-kernel use cases applies here as well.
+
+The major difference, however, is that user space can only act as a consumer
+and never as a provider of a transformation or cipher algorithm.
+
+The following covers the user space interface exported by the kernel crypto
+API. It provides a fully working sample code at the that can be used as a
+library for user space applications that require cryptographic services from
+the kernel.
+
+Some details of the in-kernel kernel crypto API aspects do not
+apply to user space, however. This includes the difference between synchronous
+and asynchronous invocations. The user space API call is fully synchronous.
+In addition, only a subset of all cipher types are available as documented
+below.
+
+
+User space API general remarks
+==============================
+
+The kernel crypto API is accessible from user space. Currently, the following
+ciphers are accessible:
+
+       * Message digest including keyed message digest (HMAC, CMAC)
+
+       * Symmetric ciphers
+
+Note, AEAD ciphers are currently not supported via the symmetric cipher
+interface.
+
+The interface is provided via Netlink using the type AF_ALG. In addition, the
+setsockopt option type is SOL_ALG. In case the user space header files do not
+export these flags yet, use the following macros:
+
+#ifndef AF_ALG
+#define AF_ALG 38
+#endif
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+A cipher is accessed with the same name as done for the in-kernel API calls.
+This includes the generic vs. unique naming schema for ciphers as well as the
+enforcement of priorities for generic names.
+
+To interact with the kernel crypto API, a Netlink socket must be created by
+the user space application. User space invokes the cipher operation with the
+send/write system call family. The result of the cipher operation is obtained
+with the read/recv system call family.
+
+The following API calls assume that the Netlink socket descriptor is already
+opened by the user space application and discusses only the kernel crypto API
+specific invocations.
+
+In-place cipher operation
+=========================
+
+Just like the in-kernel operation of the kernel crypto API, the user space
+interface allows the cipher operation in-place. That means that the input 
buffer
+used for the send/write system call and the output buffer used by the read/recv
+system call may be one and the same. This is of particular interest for
+symmetric cipher operations where a copying of the output data to its final
+destination can be avoided.
+
+Message digest API
+==================
+
+The message digest type to be used for the cipher operation is selected when
+invoking the bind syscall. bind requires the caller to provide a filled
+struct sockaddr data structure. This data structure must be filled as follows:
+
+struct sockaddr_alg sa = {
+       .salg_family = AF_ALG,
+       .salg_type = "hash", /* this selects the hash logic in the kernel */
+       .salg_name = "sha1" /* this is the cipher name */
+};
+
+The salg_type value "hash" applies to message digests and keyed message 
digests.
+Though, a keyed message digest is referenced by the appropriate salg_name and
+providing a key for the cipher operation.
+
+Using the send() system call, the application provides the data that should be
+processed with the message digest. The send system call allows the following
+flags to be specified:
+
+       * MSG_MORE: If this flag is set, the send system call acts like a
+                   message digest update function where the final hash is not
+                   yet calculated. If the flag is not set, the send system call
+                   calculates the final message digest immediately.
+
+With the recv() system call, the application can read the message digest from
+the kernel crypto API. If the buffer is too small for the message digest, the
+flag MSG_TRUNC is set by the kernel.
+
+In order to set a message digest key, the calling application must use the
+setsockopt() option of ALG_SET_KEY. If the key is not set the HMAC operation is
+performed without the initial HMAC state change caused by the key.
+
+
+Symmetric cipher API
+====================
+
+The operation is very similar to the message digest discussion. During
+initialization, the struct sockaddr data structure must be filled as follows:
+
+struct sockaddr_alg sa = {
+       .salg_family = AF_ALG,
+       .salg_type = "skcipher", /* this selects the symmetric cipher */
+       .salg_name = "cbc(aes)" /* this is the cipher name */
+};
+
+Using the sendmsg() system call, the application provides the data that should
+be processed for encryption or decryption. In addition, the IV is specified
+with the data structure provided by the sendmsg() system call.
+
+The sendmsg system call parameter of struct msghdr is embedded into the
+struct cmsghdr data structure. See recv(2) and cmsg(3) for more information
+on how the cmsghdr data structure is used together with the send/recv system
+call family. That cmsghdr data structure holds the following information
+specified with a separate header instances:
+
+       * specification of the cipher operation type with one of these flags:
+               ALG_OP_ENCRYPT - encryption of data
+               ALG_OP_DECRYPT - decryption of data
+
+       * specification of the IV information marked with the flag ALG_SET_IV
+
+The send system call family allows the following flag to be specified:
+
+       * MSG_MORE: If this flag is set, the send system call acts like a
+                   cipher update function where more input data is expected
+                   with a subsequent invocation of the send system call.
+
+Note: The kernel reports -EINVAL for any unexpected data. The caller must
+make sure that all data matches the constraints given in /proc/crypto for the
+selected cipher.
+
+With the recv() system call, the application can read the result of the
+cipher operation from the kernel crypto API. The output buffer must be at least
+as large as to hold all blocks of the encrypted or decrypted data. If the 
output
+data size is smaller, only as many blocks are returned that fit into that
+output buffer size.
+
+User space API example
+======================
+
+Compile the following code with the gcc flags of "-Wextra -Wall -pedantic".
+
+/*
+ * Generic kernel crypto API user space interface library
+ *
+ * Copyright (C) 2014, Stephan Mueller <smuel...@chronox.de>
+ *
+ * Derived from cryptsetup 1.6.4:
+ *
+ * Linux kernel user space API crypto backend implementation (skcipher)
+ *
+ * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2012, Milan Broz
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+/*
+ * Code from cryptsetup version 1.6.4 used as a basis. See files
+ * lib/crypto_backend/crypto_cipher_kernel.c and
+ * lib/crypto_backend/crypto_kernel.c
+ */
+
+#include <stdio.h>
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if_alg.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef AF_ALG
+#define AF_ALG 38
+#endif
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+/************************************************************
+ * Application interfaces
+ ************************************************************/
+
+/* Cipher handle */
+struct kcapi_handle {
+       int tfmfd;
+       int opfd;
+};
+
+/************************************************************
+ * Internal logic
+ ************************************************************/
+
+/* The in/out should be aligned to page boundary */
+static int _kcapi_cipher_crypt(struct kcapi_handle *handle,
+                              const unsigned char *in, size_t inlen,
+                              unsigned char *out, size_t outlen,
+                              const unsigned char *iv, size_t ivlen,
+                              uint32_t enc)
+{
+       int r = 0;
+       ssize_t ret;
+       struct af_alg_iv *alg_iv;
+       struct cmsghdr *header;
+       uint32_t *type;
+       struct iovec iov;
+       int iv_msg_size = iv ? CMSG_SPACE(sizeof(*alg_iv) + ivlen) : 0;
+       char *buffer = NULL;
+       volatile void *_buffer = NULL;
+       unsigned int bufferlen = CMSG_SPACE(sizeof(*type)) + iv_msg_size;
+       struct msghdr msg;
+
+       memset(&msg, 0, sizeof(msg));
+
+       if (!in || !out || !inlen || !outlen)
+               return -EINVAL;
+
+       if ((!iv && ivlen) || (iv && !ivlen))
+               return -EINVAL;
+
+       buffer = calloc(1, bufferlen);
+       if (!buffer)
+               return -ENOMEM;
+
+       iov.iov_base = (void*)(uintptr_t)in;
+       iov.iov_len = inlen;
+       msg.msg_control = buffer;
+       msg.msg_controllen = bufferlen;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+
+       /* encrypt/decrypt operation */
+       header = CMSG_FIRSTHDR(&msg);
+       header->cmsg_level = SOL_ALG;
+       header->cmsg_type = ALG_SET_OP;
+       header->cmsg_len = CMSG_LEN(sizeof(*type));
+       type = (void*)CMSG_DATA(header);
+       *type = enc;
+
+       /* set IV */
+       if (iv) {
+               header = CMSG_NXTHDR(&msg, header);
+               header->cmsg_level = SOL_ALG;
+               header->cmsg_type = ALG_SET_IV;
+               header->cmsg_len = iv_msg_size;
+               alg_iv = (void*)CMSG_DATA(header);
+               alg_iv->ivlen = ivlen;
+               memcpy(alg_iv->iv, iv, ivlen);
+       }
+
+       ret = sendmsg(handle->opfd, &msg, 0);
+       if (ret != (ssize_t)inlen) {
+               r = -EIO;
+               goto bad;
+       }
+
+       ret = read(handle->opfd, out, outlen);
+       if (ret != (ssize_t)outlen)
+               r = -EIO;
+bad:
+       memset(buffer, 0, bufferlen);
+       _buffer = memchr(buffer, 1, bufferlen);
+       if (_buffer)
+               _buffer = '\0';
+       free(buffer);
+       return r;
+}
+
+/************************************************************
+ * API to application
+ ************************************************************/
+
+/*
+ * Initialization of a cipher handle and establishing the connection to
+ * the kernel
+ *
+ * @handle cipher handle filled during the call - output
+ * @type cipher type, one of the following - input:
+ *      "hash" for message digests (including keyed message digests)
+ *      "skcipher" for symmetric ciphers
+ * @ciphername kernel crypto API cipher name as specified in
+ *            /proc/crypto - input
+ *
+ * return: 0 upon success
+ *        < 0 in case of error
+ *             ENOENT - algorithm not available
+ *             ENOTSUP - AF_ALG family not available
+ *             EINVAL - accept syscall failed
+ */
+int kcapi_cipher_init(struct kcapi_handle *handle,
+                     const char *type, const char *ciphername)
+{
+       struct sockaddr_alg sa;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.salg_family = AF_ALG;
+       snprintf((char *)sa.salg_type, sizeof(sa.salg_type),"%s", type);
+       snprintf((char *)sa.salg_name, sizeof(sa.salg_name),"%s", ciphername);
+
+       handle->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+       if (handle->tfmfd == -1)
+               return -ENOTSUP;
+
+       if (bind(handle->tfmfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
+               close(handle->tfmfd);
+               handle->tfmfd = -1;
+               return -ENOENT;
+       }
+
+       handle->opfd = accept(handle->tfmfd, NULL, 0);
+       if (handle->opfd == -1) {
+               close(handle->tfmfd);
+               handle->tfmfd = -1;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Close the cipher handle and release resources
+ *
+ * @handle cipher handle to release - input
+ *
+ * return: 0 upon success
+ */
+int kcapi_cipher_destory(struct kcapi_handle *handle)
+{
+       if (handle->tfmfd != -1)
+               close(handle->tfmfd);
+       if (handle->opfd != -1)
+               close(handle->opfd);
+       return 0;
+}
+
+
+/*
+ * Set the key for the cipher handle
+ *
+ * This call is applicable for keyed message digests and symmetric ciphers.
+ *
+ * @handle cipher handle - input
+ * @key key buffer - input
+ * @keylen length of key buffer - input
+ *
+ * return: 0 upon success
+ *        < 0 in case of error
+ */
+int kcapi_cipher_setkey(struct kcapi_handle *handle,
+                       const unsigned char *key, size_t keylen)
+{
+       if (setsockopt(handle->tfmfd, SOL_ALG, ALG_SET_KEY,
+                      key, keylen) == -1)
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * Message digest update function
+ *
+ * @handle cipher handle - input
+ * @buffer holding the data to add to the message digest - input
+ * @len buffer length - input
+ *
+ * return: 0 upon success
+ *        < 0 in case of error
+ */
+int kcapi_md_update(struct kcapi_handle *handle,
+                   const unsigned char *buffer, size_t len)
+{
+       ssize_t r;
+
+       r = send(handle->opfd, buffer, len, MSG_MORE);
+       if (r < 0 || (size_t)r < len)
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * Message digest finalization function
+ *
+ * @handle cipher handle - input
+ * @buffer filled with the message digest - output
+ * @len buffer length - input
+ *
+ * return: 0 upon success
+ *        < 0 in case of error
+ *             EIO - data cannot be obtained
+ *             ENOMEM - buffer is too small for the complete message digest,
+ *                      the buffer is filled with the truncated message digest
+ */
+
+int kcapi_md_final(struct kcapi_handle *handle,
+                  unsigned char *buffer, size_t len)
+{
+       ssize_t r;
+       struct iovec iov;
+       struct msghdr msg;
+
+       iov.iov_base = (void*)(uintptr_t)buffer;
+       iov.iov_len = len;
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+
+       r = recvmsg(handle->opfd, &msg, 0);
+       if (r < 0)
+               return -EIO;
+       if (msg.msg_flags & MSG_TRUNC)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/*
+ * Encrypt data
+ *
+ * @handle cipher handle - input
+ * @in plaintext data buffer - input
+ * @inlen length of in buffer - input
+ * @out ciphertext data buffer - output
+ * @outlen length of out buffer - input
+ * @iv buffer holding the IV (may be NULL if IV is not needed) - input
+ * @ivlen length of iv (should be zero if iv is NULL) - input
+ *
+ * return: 0 upon success
+ *        < 0 in case of error
+ */
+int kcapi_cipher_encrypt(struct kcapi_handle *handle,
+                        const unsigned char *in, size_t inlen,
+                        unsigned char *out, size_t outlen,
+                        const unsigned char *iv, size_t ivlen)
+{
+       return _kcapi_cipher_crypt(handle, in, inlen, out, outlen,
+                                  iv, ivlen, ALG_OP_ENCRYPT);
+}
+
+/*
+ * Decrypt data
+ *
+ * @handle cipher handle - input
+ * @in ciphertext data buffer - input
+ * @inlen length of in buffer - input
+ * @out plaintext data buffer - output
+ * @outlen length of out buffer - input
+ * @iv buffer holding the IV (may be NULL if IV is not needed) - input
+ * @ivlen length of iv (should be zero if iv is NULL) - input
+ *
+ * return: 0 upon success
+ *        < 0 in case of error
+ */
+int kcapi_cipher_decrypt(struct kcapi_handle *handle,
+                        const unsigned char *in, size_t inlen,
+                        unsigned char *out, size_t outlen,
+                        const unsigned char *iv, size_t ivlen)
+{
+       return _kcapi_cipher_crypt(handle, in, inlen, out, outlen,
+                                  iv, ivlen, ALG_OP_DECRYPT);
+}
+
+/************************************************************
+ * Application requiring cryptographic services
+ ************************************************************/
+
+static char hex_char_map_l[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+static char hex_char_map_u[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+static char hex_char(unsigned int bin, int u)
+{
+       if (bin < sizeof(hex_char_map_l))
+               return (u) ? hex_char_map_u[bin] : hex_char_map_l[bin];
+       return 'X';
+}
+
+/*
+ * Convert binary string into hex representation
+ * @bin input buffer with binary data
+ * @binlen length of bin
+ * @hex output buffer to store hex data
+ * @hexlen length of already allocated hex buffer (should be at least
+ *        twice binlen -- if not, only a fraction of binlen is converted)
+ * @u case of hex characters (0=>lower case, 1=>upper case)
+ */
+static void bin2hex(const unsigned char *bin, size_t binlen,
+                   char *hex, size_t hexlen, int u)
+{
+       size_t i = 0;
+       size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen;
+
+       for (i = 0; i < chars; i++) {
+               hex[(i*2)] = hex_char((bin[i] >> 4), u);
+               hex[((i*2)+1)] = hex_char((bin[i] & 0x0f), u);
+       }
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct kcapi_handle handle;
+#define BUFLEN 32
+       unsigned char inbuf[BUFLEN]; /* Plaintext */
+#define IVLEN 16
+       unsigned char ivbuf[IVLEN]; /* IV */
+       unsigned char outbuf[BUFLEN]; /* ciphertext for encryption */
+       unsigned char outbuf2[BUFLEN]; /* plaintext for decryption */
+       char hexbuf[BUFLEN * 2 + 1];
+
+       (void)argc;
+       (void)argv;
+
+       /*
+        * Calculate a message digest
+        */
+       if (kcapi_cipher_init(&handle, "hash", "sha256")) {
+               printf("Allocation of hash failed\n");
+               return(1);
+       }
+       memcpy(inbuf, "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                     "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", BUFLEN);
+       if (kcapi_md_update(&handle, inbuf, BUFLEN)) {
+               printf("Hash update of buffer failed\n");
+               return(1);
+       }
+       if (kcapi_md_final(&handle, outbuf, BUFLEN)) {
+               printf("Hash final failed\n");
+               return(1);
+       }
+       kcapi_cipher_destory(&handle);
+       memset(hexbuf, 0, BUFLEN * 2 + 1);
+       bin2hex(outbuf, BUFLEN, hexbuf, BUFLEN * 2 + 1, 0);
+       printf("Calculated hash %s\n", hexbuf);
+
+       /*
+        * Calculate a keyed message digest
+        */
+       if (kcapi_cipher_init(&handle, "hash", "hmac(sha256)")) {
+               printf("Allocation of HMAC failed\n");
+               return(1);
+       }
+       memcpy(inbuf, "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                     "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", BUFLEN);
+       if (kcapi_cipher_setkey(&handle, inbuf, BUFLEN)) {
+               printf("HMAC setkey failed\n");
+               return(1);
+       }
+       if (kcapi_md_update(&handle, inbuf, BUFLEN)) {
+               printf("HMAC update of buffer failed\n");
+               return(1);
+       }
+       if (kcapi_md_final(&handle, outbuf, BUFLEN)) {
+               printf("HMAC final failed\n");
+               return(1);
+       }
+       kcapi_cipher_destory(&handle);
+       memset(hexbuf, 0, BUFLEN * 2 + 1);
+       bin2hex(outbuf, BUFLEN, hexbuf, BUFLEN * 2 + 1, 0);
+       printf("Calculated hmac %s\n", hexbuf);
+
+       /*
+        * Encrypt data
+        */
+       if (kcapi_cipher_init(&handle, "skcipher", "cbc(aes)")) {
+               printf("Allocation of cipher failed\n");
+               return(1);
+       }
+
+       /* Set key */
+       memcpy(inbuf, "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                     "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", BUFLEN);
+       if (kcapi_cipher_setkey(&handle, inbuf, BUFLEN)) {
+               printf("AES setkey failed\n");
+               return(1);
+       }
+
+       /* Prepare IV */
+       memcpy(ivbuf, "\x00\x01\x02\x03\x04\x05\x06\x07"
+                     "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", IVLEN);
+
+       /*
+        * Encrypt inbuf -- key and plaintext are the same in this example
+        *
+        * It is perfectly legal to use inbuf for the plaintext and ciphertext
+        * pointers. That would mean that after the encryption operation, the
+        * plaintext is overwritten with the cipher text.
+        */
+       if (kcapi_cipher_encrypt(&handle, inbuf, BUFLEN,
+                                outbuf, BUFLEN, ivbuf, IVLEN)) {
+               printf("Encryption buffer failed\n");
+               return(1);
+       }
+
+       /* outbuf now contains the cipher text */
+       memset(hexbuf, 0, BUFLEN * 2 + 1);
+       bin2hex(outbuf, BUFLEN, hexbuf, BUFLEN * 2 + 1, 0);
+       printf("Encrypted data %s\n", hexbuf);
+
+       /*
+        * Decrypt previously encrypted data
+        *
+        * Just like for the encryption operation, the ciphertext buffer pointer
+        * and the plaintext buffer pointer may point to the same memory
+        * location. After completion of this operation, the ciphertext is
+        * overwritten with the plaintext.
+        */
+       if (kcapi_cipher_decrypt(&handle, outbuf, BUFLEN,
+                                outbuf2, BUFLEN, ivbuf, IVLEN)) {
+               printf("Decryption buffer failed\n");
+               return(1);
+       }
+       kcapi_cipher_destory(&handle);
+       memset(hexbuf, 0, BUFLEN * 2 + 1);
+       bin2hex(outbuf2, BUFLEN, hexbuf, BUFLEN * 2 + 1, 0);
+       printf("Decrypted data %s\n", hexbuf);
+       if (!memcmp(inbuf, outbuf2, BUFLEN))
+               printf("Decrypted data match original plaintext as expected\n");
+       else
+               printf("FAILURE: Decrypted data does not match original 
plaintext\n");
+
+       return 0;
+}
+
+Author
+======
+
+Stephan Mueller <smuel...@chronox.de>
-- 
2.1.0


--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to