]> code.ossystems Code Review - meta-freescale.git/blob
033552a34a787e8937c438e46a4d7be42f96ed97
[meta-freescale.git] /
1 From 8cabaedb69acc5b44c7a9cf058045908130a6af7 Mon Sep 17 00:00:00 2001
2 From: Cristian Stoica <cristian.stoica@freescale.com>
3 Date: Wed, 23 Oct 2013 16:57:22 +0300
4 Subject: [[Patch][fsl 03/16] Add support for aead keys for composite
5  algorithms
6
7 Upstream-status: Pending
8
9 Composite aead algorithms (e.g. AES-CBC + HMAC-SHA1) need two keys to
10 operate. The two keys are wrapped in a single buffer in the form
11 used also by crypto/authenc.c
12 Blockcipher and non-composite aead algorithms (e.g. AES-GCM) use a
13 single key which is simply copied from user-space.
14
15 Signed-off-by: Cristian Stoica <cristian.stoica@freescale.com>
16 Tested-by: Horia Ioan Geanta Neag <horia.geanta@freescale.com>
17 ---
18  cryptlib.c |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19  cryptlib.h |    3 +++
20  ioctl.c    |   24 ++++++++++++++----------
21  3 files changed, 76 insertions(+), 10 deletions(-)
22
23 diff --git a/cryptlib.c b/cryptlib.c
24 index a7fbff4..2986d09 100644
25 --- a/cryptlib.c
26 +++ b/cryptlib.c
27 @@ -34,6 +34,8 @@
28  #include <crypto/hash.h>
29  #include <crypto/cryptodev.h>
30  #include <crypto/aead.h>
31 +#include <linux/rtnetlink.h>
32 +#include <crypto/authenc.h>
33  #include "cryptodev_int.h"
34  
35  
36 @@ -53,6 +55,63 @@ static void cryptodev_complete(struct crypto_async_request *req, int err)
37         complete(&res->completion);
38  }
39  
40 +int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
41 +               int aead)
42 +{
43 +       unsigned int klen = sop->keylen;
44 +
45 +       if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN))
46 +               return -EINVAL;
47 +
48 +       if (aead && sop->mackeylen) {
49 +               if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN))
50 +                       return -EINVAL;
51 +               klen += sop->mackeylen;
52 +               klen += RTA_SPACE(sizeof(struct crypto_authenc_key_param));
53 +       }
54 +
55 +       *keylen = klen;
56 +       return 0;
57 +}
58 +
59 +int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead)
60 +{
61 +       /* Get algorithm key from user-space. For composite aead algorithms,
62 +        * the key representation is in the format used by linux kernel in
63 +        * crypto/authenc.c
64 +        */
65 +       struct crypto_authenc_key_param *param;
66 +       struct rtattr *rta;
67 +       int ret = 0;
68 +
69 +       if (aead && sop->mackeylen) {
70 +               /* the key header type and header length */
71 +               rta = (void *)key;
72 +               rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
73 +               rta->rta_len = RTA_LENGTH(sizeof(*param));
74 +
75 +               /* the key parameter is the length of the encryption key */
76 +               param = RTA_DATA(rta);
77 +               param->enckeylen = cpu_to_be32(sop->keylen);
78 +
79 +               /* copy the hash key */
80 +               key += RTA_SPACE(sizeof(*param));
81 +               if (unlikely(copy_from_user(key, sop->mackey, sop->mackeylen))) {
82 +                       ret = -EFAULT;
83 +                       goto error;
84 +               }
85 +               /* get the pointer ready for the encryption key */
86 +               key += sop->mackeylen;
87 +       }
88 +       /* blockcipher algorithms have the key ready to use */
89 +       if (unlikely(copy_from_user(key, sop->key, sop->keylen)))
90 +               ret = -EFAULT;
91 +
92 +error:
93 +       return ret;
94 +}
95 +
96 +
97  int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
98                                 uint8_t *keyp, size_t keylen, int stream, int aead)
99  {
100 diff --git a/cryptlib.h b/cryptlib.h
101 index 0744284..a0a8a63 100644
102 --- a/cryptlib.h
103 +++ b/cryptlib.h
104 @@ -25,6 +25,9 @@ struct cipher_data {
105  int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name,
106                           uint8_t *key, size_t keylen, int stream, int aead);
107  void cryptodev_cipher_deinit(struct cipher_data *cdata);
108 +int cryptodev_get_cipher_key(uint8_t *key, struct session_op *sop, int aead);
109 +int cryptodev_get_cipher_keylen(unsigned int *keylen, struct session_op *sop,
110 +               int aead);
111  ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata,
112                         const struct scatterlist *sg1,
113                         struct scatterlist *sg2, size_t len);
114 diff --git a/ioctl.c b/ioctl.c
115 index c614373..3baf195 100644
116 --- a/ioctl.c
117 +++ b/ioctl.c
118 @@ -109,7 +109,8 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
119         const char *alg_name = NULL;
120         const char *hash_name = NULL;
121         int hmac_mode = 1, stream = 0, aead = 0;
122 -       uint8_t enckey[CRYPTO_CIPHER_MAX_KEY_LEN];
123 +       uint8_t *key = NULL;
124 +       unsigned int keylen;
125         uint8_t mackey[CRYPTO_HMAC_MAX_KEY_LEN];
126  
127         /* Does the request make sense? */
128 @@ -229,20 +230,22 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
129  
130         /* Set-up crypto transform. */
131         if (alg_name) {
132 -               if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
133 -                       ddebug(1, "Setting key failed for %s-%zu.",
134 -                               alg_name, (size_t)sop->keylen*8);
135 -                       ret = -EINVAL;
136 +               ret = cryptodev_get_cipher_keylen(&keylen, sop, aead);
137 +               if (unlikely(ret < 0))
138                         goto error_cipher;
139 -               }
140  
141 -               if (unlikely(copy_from_user(enckey, sop->key, sop->keylen))) {
142 -                       ret = -EFAULT;
143 +               key = kmalloc(keylen, GFP_KERNEL);
144 +               if (unlikely(!key)) {
145 +                       ret = -ENOMEM;
146                         goto error_cipher;
147                 }
148  
149 -               ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, enckey,
150 -                                               sop->keylen, stream, aead);
151 +               ret = cryptodev_get_cipher_key(key, sop, aead);
152 +               if (unlikely(ret < 0))
153 +                       goto error_cipher;
154 +
155 +               ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, key, keylen,
156 +                               stream, aead);
157                 if (ret < 0) {
158                         ddebug(1, "Failed to load cipher for %s", alg_name);
159                         ret = -EINVAL;
160 @@ -318,6 +321,7 @@ error_hash:
161         kfree(ses_new->sg);
162         kfree(ses_new->pages);
163  error_cipher:
164 +       kfree(key);
165         kfree(ses_new);
166  
167         return ret;
168 -- 
169 1.7.9.7
170