From: Cristian Stoica <cristian.sto...@freescale.com> Composite aead algorithms (e.g. AES-CBC + HMAC-SHA1) need two keys to operate. The two keys are wrapped in a single buffer in the form used also by crypto/authenc.c Blockcipher and non-composite aead algorithms (e.g. AES-GCM) use a single key which is simply copied from user-space.
Signed-off-by: Cristian Stoica <cristian.sto...@freescale.com> Reviewed-by: Mircea Pop <mircea....@freescale.com> Reviewed-by: Alexandru Porosanu <alexandru.poros...@freescale.com> Reviewed-by: Horia Ioan Geanta Neag <horia.gea...@freescale.com> Tested-by: Horia Ioan Geanta Neag <horia.gea...@freescale.com> Signed-off-by: Horia Geanta <horia.gea...@freescale.com> --- cryptlib.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ cryptlib.h | 3 ++ cryptodev_int.h | 1 + ioctl.c | 30 +++++++++++++++------------ 4 files changed, 80 insertions(+), 13 deletions(-) diff --git a/cryptlib.c b/cryptlib.c index 90fb491..0fac041 100644 --- a/cryptlib.c +++ b/cryptlib.c @@ -34,6 +34,8 @@ #include <crypto/hash.h> #include <crypto/cryptodev.h> #include <crypto/aead.h> +#include <linux/rtnetlink.h> +#include <crypto/authenc.h> #include "cryptodev_int.h" @@ -53,6 +55,63 @@ static void cryptodev_complete(struct crypto_async_request *req, int err) complete(&res->completion); } +int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, + int aead) +{ + unsigned int klen = sop->keylen; + + if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) + return -EINVAL; + + if (aead && sop->mackeylen) { + if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) + return -EINVAL; + klen += sop->mackeylen; + klen += RTA_SPACE(sizeof(struct crypto_authenc_key_param)); + } + + *keylen = klen; + return 0; +} + +int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead) +{ + /* Get algorithm key from user-space. For composite aead algorithms, + * the key representation is in the format used by linux kernel in + * crypto/authenc.c + */ + struct crypto_authenc_key_param *param; + struct rtattr *rta; + int ret = 0; + + if (aead && sop->mackeylen) { + /* the key header type and header length */ + rta = (void *)key; + rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; + rta->rta_len = RTA_LENGTH(sizeof(*param)); + + /* the key parameter is the length of the encryption key */ + param = RTA_DATA(rta); + param->enckeylen = cpu_to_be32(sop->keylen); + + /* copy the hash key */ + key += RTA_SPACE(sizeof(*param)); + if (unlikely(copy_from_user(key, sop->mackey, sop->mackeylen))) { + ret = -EFAULT; + goto error; + } + /* get the pointer ready for the encryption key */ + key += sop->mackeylen; + } + /* blockcipher algorithms have the key ready to use */ + if (unlikely(copy_from_user(key, sop->key, sop->keylen))) + ret = -EFAULT; + +error: + return ret; +} + + int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, uint8_t *keyp, unsigned int keylen, int stream, int aead) { diff --git a/cryptlib.h b/cryptlib.h index 714ab04..ffb5935 100644 --- a/cryptlib.h +++ b/cryptlib.h @@ -25,6 +25,9 @@ struct cipher_data { int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, uint8_t *key, unsigned int keylen, int stream, int aead); void cryptodev_cipher_deinit(struct cipher_data *cdata); +int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead); +int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop, + int aead); ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len); diff --git a/cryptodev_int.h b/cryptodev_int.h index 12dd5b1..e3e3e10 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -114,6 +114,7 @@ struct csession { struct hash_data hdata; uint32_t sid; uint32_t alignmask; + uint8_t *key; unsigned int array_size; unsigned int used_pages; /* the number of pages that are used */ diff --git a/ioctl.c b/ioctl.c index 5a34c74..a8500ef 100644 --- a/ioctl.c +++ b/ioctl.c @@ -109,7 +109,8 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) const char *alg_name = NULL; const char *hash_name = NULL; int hmac_mode = 1, stream = 0, aead = 0; - uint8_t enckey[CRYPTO_CIPHER_MAX_KEY_LEN]; + uint8_t *key = NULL; + unsigned int keylen; uint8_t mackey[CRYPTO_HMAC_MAX_KEY_LEN]; /* Does the request make sense? */ @@ -224,24 +225,25 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) /* Set-up crypto transform. */ if (alg_name) { - if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) { - dprintk(1, KERN_DEBUG, - "Setting key failed for %s-%u.\n", - alg_name, sop->keylen*8); - ret = -EINVAL; + ret = cryptodev_get_cipher_keylen(&keylen, sop, aead); + if (unlikely(ret < 0)) goto error_cipher; - } - if (unlikely(copy_from_user(enckey, sop->key, sop->keylen))) { - ret = -EFAULT; + key = kmalloc(keylen, GFP_KERNEL); + ses_new->key = key; + if (unlikely(!key)) { + ret = -ENOMEM; goto error_cipher; } - ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, enckey, - sop->keylen, stream, aead); + ret = cryptodev_get_cipher_key(key, sop, aead); + if (unlikely(ret < 0)) + goto error_cipher; + + ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, key, keylen, + stream, aead); if (ret < 0) { - dprintk(1, KERN_DEBUG, - "Failed to load cipher for %s\n", alg_name); + dprintk(1, KERN_DEBUG, "Failed to load cipher %s\n", alg_name); ret = -EINVAL; goto error_cipher; } @@ -317,6 +319,7 @@ error_hash: kfree(ses_new->sg); kfree(ses_new->pages); error_cipher: + kfree(key); kfree(ses_new); return ret; @@ -339,6 +342,7 @@ crypto_destroy_session(struct csession *ses_ptr) ses_ptr->array_size); kfree(ses_ptr->pages); kfree(ses_ptr->sg); + kfree(ses_ptr->key); mutex_unlock(&ses_ptr->sem); mutex_destroy(&ses_ptr->sem); kfree(ses_ptr); -- 1.7.7.6 _______________________________________________ Cryptodev-linux-devel mailing list Cryptodev-linux-devel@gna.org https://mail.gna.org/listinfo/cryptodev-linux-devel