Merge remote-tracking branch 'lsk/v3.10/topic/gator' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / crypto / aes-ce-ccm-glue.c
1 /*
2  * aes-ccm-glue.c - AES-CCM transform for ARMv8 with Crypto Extensions
3  *
4  * Copyright (C) 2013 - 2014 Linaro Ltd <ard.biesheuvel@linaro.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <asm/neon.h>
12 #include <asm/unaligned.h>
13 #include <crypto/aes.h>
14 #include <crypto/algapi.h>
15 #include <crypto/scatterwalk.h>
16 #include <linux/crypto.h>
17 #include <linux/module.h>
18
19 static int num_rounds(struct crypto_aes_ctx *ctx)
20 {
21         /*
22          * # of rounds specified by AES:
23          * 128 bit key          10 rounds
24          * 192 bit key          12 rounds
25          * 256 bit key          14 rounds
26          * => n byte key        => 6 + (n/4) rounds
27          */
28         return 6 + ctx->key_length / 4;
29 }
30
31 asmlinkage void ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes,
32                                      u32 *macp, u32 const rk[], u32 rounds);
33
34 asmlinkage void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes,
35                                    u32 const rk[], u32 rounds, u8 mac[],
36                                    u8 ctr[]);
37
38 asmlinkage void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes,
39                                    u32 const rk[], u32 rounds, u8 mac[],
40                                    u8 ctr[]);
41
42 asmlinkage void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u32 const rk[],
43                                  u32 rounds);
44
45 static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key,
46                       unsigned int key_len)
47 {
48         struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm);
49         int ret;
50
51         ret = crypto_aes_expand_key(ctx, in_key, key_len);
52         if (!ret)
53                 return 0;
54
55         tfm->base.crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
56         return -EINVAL;
57 }
58
59 static int ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
60 {
61         if ((authsize & 1) || authsize < 4)
62                 return -EINVAL;
63         return 0;
64 }
65
66 static int ccm_init_mac(struct aead_request *req, u8 maciv[], u32 msglen)
67 {
68         struct crypto_aead *aead = crypto_aead_reqtfm(req);
69         __be32 *n = (__be32 *)&maciv[AES_BLOCK_SIZE - 8];
70         u32 l = req->iv[0] + 1;
71
72         /* verify that CCM dimension 'L' is set correctly in the IV */
73         if (l < 2 || l > 8)
74                 return -EINVAL;
75
76         /* verify that msglen can in fact be represented in L bytes */
77         if (l < 4 && msglen >> (8 * l))
78                 return -EOVERFLOW;
79
80         /*
81          * Even if the CCM spec allows L values of up to 8, the Linux cryptoapi
82          * uses a u32 type to represent msglen so the top 4 bytes are always 0.
83          */
84         n[0] = 0;
85         n[1] = cpu_to_be32(msglen);
86
87         memcpy(maciv, req->iv, AES_BLOCK_SIZE - l);
88
89         /*
90          * Meaning of byte 0 according to CCM spec (RFC 3610/NIST 800-38C)
91          * - bits 0..2  : max # of bytes required to represent msglen, minus 1
92          *                (already set by caller)
93          * - bits 3..5  : size of auth tag (1 => 4 bytes, 2 => 6 bytes, etc)
94          * - bit 6      : indicates presence of authenticate-only data
95          */
96         maciv[0] |= (crypto_aead_authsize(aead) - 2) << 2;
97         if (req->assoclen)
98                 maciv[0] |= 0x40;
99
100         memset(&req->iv[AES_BLOCK_SIZE - l], 0, l);
101         return 0;
102 }
103
104 static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[])
105 {
106         struct crypto_aead *aead = crypto_aead_reqtfm(req);
107         struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
108         struct __packed { __be16 l; __be32 h; u16 len; } ltag;
109         struct scatter_walk walk;
110         u32 len = req->assoclen;
111         u32 macp = 0;
112
113         /* prepend the AAD with a length tag */
114         if (len < 0xff00) {
115                 ltag.l = cpu_to_be16(len);
116                 ltag.len = 2;
117         } else  {
118                 ltag.l = cpu_to_be16(0xfffe);
119                 put_unaligned_be32(len, &ltag.h);
120                 ltag.len = 6;
121         }
122
123         ce_aes_ccm_auth_data(mac, (u8 *)&ltag, ltag.len, &macp, ctx->key_enc,
124                              num_rounds(ctx));
125         scatterwalk_start(&walk, req->assoc);
126
127         do {
128                 u32 n = scatterwalk_clamp(&walk, len);
129                 u8 *p;
130
131                 if (!n) {
132                         scatterwalk_start(&walk, sg_next(walk.sg));
133                         n = scatterwalk_clamp(&walk, len);
134                 }
135                 p = scatterwalk_map(&walk);
136                 ce_aes_ccm_auth_data(mac, p, n, &macp, ctx->key_enc,
137                                      num_rounds(ctx));
138                 len -= n;
139
140                 scatterwalk_unmap(p);
141                 scatterwalk_advance(&walk, n);
142                 scatterwalk_done(&walk, 0, len);
143         } while (len);
144 }
145
146 static int ccm_encrypt(struct aead_request *req)
147 {
148         struct crypto_aead *aead = crypto_aead_reqtfm(req);
149         struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
150         struct blkcipher_desc desc = { .info = req->iv };
151         struct blkcipher_walk walk;
152         u8 __aligned(8) mac[AES_BLOCK_SIZE];
153         u8 buf[AES_BLOCK_SIZE];
154         u32 len = req->cryptlen;
155         int err;
156
157         err = ccm_init_mac(req, mac, len);
158         if (err)
159                 return err;
160
161         kernel_neon_begin_partial(6);
162
163         if (req->assoclen)
164                 ccm_calculate_auth_mac(req, mac);
165
166         /* preserve the original iv for the final round */
167         memcpy(buf, req->iv, AES_BLOCK_SIZE);
168
169         blkcipher_walk_init(&walk, req->dst, req->src, len);
170         err = blkcipher_aead_walk_virt_block(&desc, &walk, aead,
171                                              AES_BLOCK_SIZE);
172
173         while (walk.nbytes) {
174                 u32 tail = walk.nbytes % AES_BLOCK_SIZE;
175
176                 if (walk.nbytes == len)
177                         tail = 0;
178
179                 ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
180                                    walk.nbytes - tail, ctx->key_enc,
181                                    num_rounds(ctx), mac, walk.iv);
182
183                 len -= walk.nbytes - tail;
184                 err = blkcipher_walk_done(&desc, &walk, tail);
185         }
186         if (!err)
187                 ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
188
189         kernel_neon_end();
190
191         if (err)
192                 return err;
193
194         /* copy authtag to end of dst */
195         scatterwalk_map_and_copy(mac, req->dst, req->cryptlen,
196                                  crypto_aead_authsize(aead), 1);
197
198         return 0;
199 }
200
201 static int ccm_decrypt(struct aead_request *req)
202 {
203         struct crypto_aead *aead = crypto_aead_reqtfm(req);
204         struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
205         unsigned int authsize = crypto_aead_authsize(aead);
206         struct blkcipher_desc desc = { .info = req->iv };
207         struct blkcipher_walk walk;
208         u8 __aligned(8) mac[AES_BLOCK_SIZE];
209         u8 buf[AES_BLOCK_SIZE];
210         u32 len = req->cryptlen - authsize;
211         int err;
212
213         err = ccm_init_mac(req, mac, len);
214         if (err)
215                 return err;
216
217         kernel_neon_begin_partial(6);
218
219         if (req->assoclen)
220                 ccm_calculate_auth_mac(req, mac);
221
222         /* preserve the original iv for the final round */
223         memcpy(buf, req->iv, AES_BLOCK_SIZE);
224
225         blkcipher_walk_init(&walk, req->dst, req->src, len);
226         err = blkcipher_aead_walk_virt_block(&desc, &walk, aead,
227                                              AES_BLOCK_SIZE);
228
229         while (walk.nbytes) {
230                 u32 tail = walk.nbytes % AES_BLOCK_SIZE;
231
232                 if (walk.nbytes == len)
233                         tail = 0;
234
235                 ce_aes_ccm_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
236                                    walk.nbytes - tail, ctx->key_enc,
237                                    num_rounds(ctx), mac, walk.iv);
238
239                 len -= walk.nbytes - tail;
240                 err = blkcipher_walk_done(&desc, &walk, tail);
241         }
242         if (!err)
243                 ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
244
245         kernel_neon_end();
246
247         if (err)
248                 return err;
249
250         /* compare calculated auth tag with the stored one */
251         scatterwalk_map_and_copy(buf, req->src, req->cryptlen - authsize,
252                                  authsize, 0);
253
254         if (memcmp(mac, buf, authsize))
255                 return -EBADMSG;
256         return 0;
257 }
258
259 static struct crypto_alg ccm_aes_alg = {
260         .cra_name               = "ccm(aes)",
261         .cra_driver_name        = "ccm-aes-ce",
262         .cra_priority           = 300,
263         .cra_flags              = CRYPTO_ALG_TYPE_AEAD,
264         .cra_blocksize          = 1,
265         .cra_ctxsize            = sizeof(struct crypto_aes_ctx),
266         .cra_alignmask          = 7,
267         .cra_type               = &crypto_aead_type,
268         .cra_module             = THIS_MODULE,
269         .cra_aead = {
270                 .ivsize         = AES_BLOCK_SIZE,
271                 .maxauthsize    = AES_BLOCK_SIZE,
272                 .setkey         = ccm_setkey,
273                 .setauthsize    = ccm_setauthsize,
274                 .encrypt        = ccm_encrypt,
275                 .decrypt        = ccm_decrypt,
276         }
277 };
278
279 static int __init aes_mod_init(void)
280 {
281         if (!(elf_hwcap & HWCAP_AES))
282                 return -ENODEV;
283         return crypto_register_alg(&ccm_aes_alg);
284 }
285
286 static void __exit aes_mod_exit(void)
287 {
288         crypto_unregister_alg(&ccm_aes_alg);
289 }
290
291 module_init(aes_mod_init);
292 module_exit(aes_mod_exit);
293
294 MODULE_DESCRIPTION("Synchronous AES in CCM mode using ARMv8 Crypto Extensions");
295 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
296 MODULE_LICENSE("GPL v2");
297 MODULE_ALIAS("ccm(aes)");