On Thu, Oct 16, 2014 at 09:25:01AM -0400, Jason Cooper wrote: > + Grant, Geert, oops. It helps if I actually *add* them. Sorry for the noise. > Stephan has created some great example code for both the kernel crypto > API and the userspace crypto API. As examples tend to bitrot, I was > wondering if the code could serve as test code. Then it would have a > triple role: API regression testing, crypto test suite, and reference > implementation. > > Original patch is here: > > https://lkml.kernel.org/r/7502136.9BkWHTZ0th@xxxxxxxxxxxxxxx > > On Thu, Oct 16, 2014 at 09:19:08AM +0200, Stephan Mueller wrote: > > Am Mittwoch, 15. Oktober 2014, 13:58:00 schrieb Jason Cooper: > > > > Hi Jason, > > > > > Stephan, > > > > > > Wow. This is very thorough. Herbert and others will be making the > > > final call on this, but if I may make a suggestion: > > > > Thanks. > > > > > > On Tue, Oct 14, 2014 at 09:46:50PM +0200, Stephan Mueller wrote: > > > > The update adds a complete interface documentation of the kernel crypto > > > > API. All cipher types supported by the kernel crypto API are documented. > > > > > > > > In addition, kernel and user space example code is provided. The sample > > > > code covers synchronous and asynchronous cipher operation, random > > > > number generation and performing hashing as well as encryption and > > > > decryption in user space. > > > > > > This really needs to be split into at least two pieces. The kernel and > > > the userspace API. I'd venture to say the userspace API portion of this > > > document is almost ready. But I'm not certain that the kernel > > > interfaces are best described in a specification. > > > > Good idea, I will split it. > > > > > > APIs within the kernel are intentionally not nailed down and are very > > > fluid. Any attempt to spell them out in a document would mean either a) > > > the document would be out of date quickly, or b) the maintainer now has > > > to ask for changes to the docs every time a patch with a kernel API > > > change comes in. Neither scenario is good. :-( > > > > Right, but on the other hand having no documentation at all is also bad. I > > know first hand how non-straight-forward it is to use the kernel crypto API as > > I programmed a test kernel module that invokes all cipher types available. > > Even with the examples in testmgr.c, I had a number of trial and errors. For > > crypto, this is not good. > > > > Note, the mistakes you make are not easily seen, which is a problem if you > > want to protect data :-) > > > > The key problem is that the kernel crypto API makes some assumptions on the > > memory layout and the concept of asymmetric requests. Furthermore, the AEAD > > definitions require different data types than offered by the API. That means > > the calling code must first massage the AEAD input data (see CCM IV vs nonce > > or the CCM/GCM tag handling). > > > > Yet, I also see that a separate documentation may easily deviate from the real > > code (I know that first hand as I have to document parts of the kernel for > > some projects :-) ). Therefore I also suggested to take the API call > > documentation out and put it into the header files where the API calls are > > specified. > > > > > > We certainly don't want to lose all of the effort you've put into > > > grokking the API, so we need to find a maintainable place to add it. I > > > personally think adding comments above the respective function > > > blocks would work well. > > > > Right, as I also suggested in my follow-up email. Yet, I would like to hear an > > ok from the maintainers that I can touch these files. > > That's like asking if you can ask a question. Just do it. :-) > > > > The examples (kernel API) are another matter entirely. Examples that > > > aren't up-to-date and usable as a template aren't helpful to anyone. > > > Some would even say detrimental. And since example code isn't actually > > > *used* in the real world, it would be an extra burden keeping it up to > > > date. I think these could best be used as a reference to compare all of > > > the current users to. Anything not up to par would generate a patch. > > > The best examples should be the current users in the kernel. > > > > Yes, that is what I also fear. Yet, using the asynchronous API may not be > > straight forward. Especially AEAD has some non-obvious requirements that may > > be documented best with an example. Yet, the example may be stripped down > > drastically to focus on the key aspects. > > Perhaps extending testmgr.c with your example code would be the best > answer. There has been a push recently to have more comprehensive test > suites within the kernel. If the test code is run often, it would make > a reasonable place for 'reference' implementations. > > > > > Signed-off-by: Stephan Mueller <smueller@xxxxxxxxxx> > > > > --- > > > > > > > > Documentation/crypto/crypto-API-spec.txt | 2110 > > > > ++++++++++++++++++++++++++++++ 1 file changed, 2110 insertions(+) > > > > create mode 100644 Documentation/crypto/crypto-API-spec.txt > > > > > > > > diff --git a/Documentation/crypto/crypto-API-spec.txt > > > > b/Documentation/crypto/crypto-API-spec.txt new file mode 100644 > > > > index 0000000..027fd4f > > > > --- /dev/null > > > > +++ b/Documentation/crypto/crypto-API-spec.txt > > > > @@ -0,0 +1,2110 @@ > > > > > > [snip detailed explanation of current kernel API] > > > > > > > +User space API > > > > +============== > > > > + > > > > +The kernel crypto API is accessible from user space. Currently, the > > > > following +ciphers are accessible: > > > > + > > > > + * Message digest including keyed message digest > > > > + > > > > + * Symmetric ciphers > > > > + > > > > +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. > > > Perhaps a reference here to the final location of the kernel API > > > explanations? > > > > As I have now split out the user space API documentation from the rest. That > > document now refers back to the initial kernel-related API document. > > > > That said, I added a precise reference to the cipher name documentation. > > > > > > > + > > > > +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. > > > > + > > > > +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_nmae = "sha1" /* this is the cipher name */ > > > > +}; > > > > + > > > > +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 read() 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. > > > > > > What happens if this is omitted? > > > > Added: > > > > "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 read() 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 the as many blocks are returned > > > > that fit into that > > > ...only as many blocks... > > > > Fixed > > > > > > > +output buffer size. > > > > + > > > > +User space API example > > > > +---------------------- > > > > + > > > > +Compile the following code with the gcc flags of "-Wextra -Wall > > > > -pedantic". + > > > > +/* > > > > + * Code from cryptsetup version 1.6.4 used as a basis > > > > + */ > > > > > > Could you specify the git commit and file from cryptsetup? This way, if > > > the this example becomes out of date, users could easily jump to the > > > newest version of working code used in the real world. > > > > I have not added the git commit as I think the version number is precise. Yet > > I added the files containing the implementation. > > > > I would think that the user space API would not change as much as the kernel > > API could considering the standard approach by the kernel developers with user > > space APIs in general. > > Agreed. > > I got to thinking about this some more last night. Why don't we split > out the below example code and make it a part of the kernel test > harness? It could test for API regressions, and be a reference > implementation at the same time... > > > > > + > > > > +#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; > > > > + unsigned int bufferlen = CMSG_SPACE(sizeof(*type)) + iv_msg_size; > > > > + struct msghdr 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); > > > > > > Not related to this patch, but you should take a look at: > > > > > > http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html > > > > > > http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient. > > > html > > > > Absolutely. Thanks for hinting to that. I added a memchr after the memset: > > > > 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]; > > > > +#define IVLEN 16 > > > > + unsigned char ivbuf[IVLEN]; > > > > + unsigned char outbuf[BUFLEN]; > > > > + unsigned char outbuf2[BUFLEN]; > > > > + 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); > > > > > > Did you test building this? > > > > Yes, I did and it worked flawlessly. Just copy out the code and compile as > > stated in the comments. What are your concerns? > > I just spotted 'destory' and casually mentioned it without grepping for > the other instances. :( It looks like it's been mis-spelled > consistently. :-P > > > See the following code where I call kcapi_cipher_init again. > > > > > > > + 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); > > > > + } > > > > + 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); > > > > + } > > > > + memcpy(ivbuf, "\x00\x01\x02\x03\x04\x05\x06\x07" > > > > + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", IVLEN); > > > > + if (kcapi_cipher_encrypt(&handle, inbuf, BUFLEN, > > > > + outbuf, BUFLEN, ivbuf, IVLEN)) { > > > > + printf("Encryption buffer failed\n"); > > > > + return(1); > > > > + } > > > > + memset(hexbuf, 0, BUFLEN * 2 + 1); > > > > + bin2hex(outbuf, BUFLEN, hexbuf, BUFLEN * 2 + 1, 0); > > > > + printf("Encrypted data %s\n", hexbuf); > > > > + > > > > + /* > > > > + * Decrypt previously encrypted data > > > > + */ > > > > + 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; > > > > +} > > > > + > > > > +License of code > > > > +=============== > > > > +/* > > > > + * Copyright (C) 2014, Stephan Mueller <smueller@xxxxxxxxxx> > > > > + * > > > > + * Redistribution and use in source and binary forms, with or without > > > > + * modification, are permitted provided that the following conditions > > > > + * are met: > > > > + * 1. Redistributions of source code must retain the above copyright > > > > + * notice, and the entire permission notice in its entirety, > > > > + * including the disclaimer of warranties. > > > > + * 2. Redistributions in binary form must reproduce the above copyright > > > > + * notice, this list of conditions and the following disclaimer in the > > > > + * documentation and/or other materials provided with the > > > > distribution. > > > > + * 3. The name of the author may not be used to endorse or promote > > > > + * products derived from this software without specific prior > > > > + * written permission. > > > > + * > > > > + * ALTERNATIVELY, this product may be distributed under the terms of > > > > + * the GNU General Public License, in which case the provisions of the > > > > GPL2 are + * required INSTEAD OF the above restrictions. (This clause is > > > > + * necessary due to a potential bad interaction between the GPL and > > > > + * the restrictions contained in a BSD-style copyright.) > > > > + * > > > > + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED > > > > + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > > > > + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF > > > > + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE > > > > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > > > > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT > > > > + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > > > > + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF > > > > + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > > > > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE > > > > + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH > > > > + * DAMAGE. > > > > + */ > > > > > > Perhaps the userspace API example should be a separate file with this > > > text at the top? Seems odd having it at the end. Also, if you copied > > > it from cryptsetup, is the copyright info correct? > > > > I did not copy it from cryptsetup. I only used it as a basis, especially with > > the data structure handling in _kcapi_cipher_crypt. But you are right, I > > changed the license for the user space by taking the cryptsetup license. > > Ok. It looks like Geert and Grant took part in the kernel test > unconference, so I'm adding them to the Cc. I hope they can give us > some pointers as to where we could hook in this code. Then we can > simply refer to it from the userspace API document. > > thx, > > Jason. -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html