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

Reply via email to