diff options
author | Mikko Herranen <mh1@iki.fi> | 2007-11-26 09:12:07 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-10 16:16:23 -0500 |
commit | e3a4ea4fd2e5f154ae9233f1ce30e7564e5cbcfc (patch) | |
tree | 8564aa42c333db6170cdc5dfc93e7a82bc315b27 | |
parent | ff85a8082f0665fe6f79d50eb79bdccb98cabfa2 (diff) |
[CRYPTO] tcrypt: Add aead support
Add AEAD support to tcrypt, needed by GCM.
Signed-off-by: Mikko Herranen <mh1@iki.fi>
Reviewed-by: Mika Kukkonen <mika.kukkonen@nsn.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | crypto/tcrypt.c | 258 | ||||
-rw-r--r-- | crypto/tcrypt.h | 22 |
2 files changed, 271 insertions, 9 deletions
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index b8cb1d1420ae..b343d81d20c9 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c | |||
@@ -6,12 +6,14 @@ | |||
6 | * | 6 | * |
7 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> | 7 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> |
8 | * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> | 8 | * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> |
9 | * Copyright (c) 2007 Nokia Siemens Networks | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the Free | 12 | * under the terms of the GNU General Public License as published by the Free |
12 | * Software Foundation; either version 2 of the License, or (at your option) | 13 | * Software Foundation; either version 2 of the License, or (at your option) |
13 | * any later version. | 14 | * any later version. |
14 | * | 15 | * |
16 | * 2007-11-13 Added AEAD support | ||
15 | * 2007-11-06 Added SHA-224 and SHA-224-HMAC tests | 17 | * 2007-11-06 Added SHA-224 and SHA-224-HMAC tests |
16 | * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests | 18 | * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests |
17 | * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>) | 19 | * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>) |
@@ -72,6 +74,7 @@ static unsigned int sec; | |||
72 | 74 | ||
73 | static int mode; | 75 | static int mode; |
74 | static char *xbuf; | 76 | static char *xbuf; |
77 | static char *axbuf; | ||
75 | static char *tvmem; | 78 | static char *tvmem; |
76 | 79 | ||
77 | static char *check[] = { | 80 | static char *check[] = { |
@@ -169,6 +172,7 @@ static void test_hash(char *algo, struct hash_testvec *template, | |||
169 | 172 | ||
170 | /* setup the dummy buffer first */ | 173 | /* setup the dummy buffer first */ |
171 | memset(xbuf, 0, XBUFSIZE); | 174 | memset(xbuf, 0, XBUFSIZE); |
175 | memset(axbuf, 0, XBUFSIZE); | ||
172 | 176 | ||
173 | j = 0; | 177 | j = 0; |
174 | for (i = 0; i < tcount; i++) { | 178 | for (i = 0; i < tcount; i++) { |
@@ -217,6 +221,233 @@ out: | |||
217 | crypto_free_hash(tfm); | 221 | crypto_free_hash(tfm); |
218 | } | 222 | } |
219 | 223 | ||
224 | static void test_aead(char *algo, int enc, struct aead_testvec *template, | ||
225 | unsigned int tcount) | ||
226 | { | ||
227 | unsigned int ret, i, j, k, temp; | ||
228 | unsigned int tsize; | ||
229 | char *q; | ||
230 | struct crypto_aead *tfm; | ||
231 | char *key; | ||
232 | struct aead_testvec *aead_tv; | ||
233 | struct aead_request *req; | ||
234 | struct scatterlist sg[8]; | ||
235 | struct scatterlist asg[8]; | ||
236 | const char *e; | ||
237 | struct tcrypt_result result; | ||
238 | |||
239 | if (enc == ENCRYPT) | ||
240 | e = "encryption"; | ||
241 | else | ||
242 | e = "decryption"; | ||
243 | |||
244 | printk(KERN_INFO "\ntesting %s %s\n", algo, e); | ||
245 | |||
246 | tsize = sizeof(struct aead_testvec); | ||
247 | tsize *= tcount; | ||
248 | |||
249 | if (tsize > TVMEMSIZE) { | ||
250 | printk(KERN_INFO "template (%u) too big for tvmem (%u)\n", | ||
251 | tsize, TVMEMSIZE); | ||
252 | return; | ||
253 | } | ||
254 | |||
255 | memcpy(tvmem, template, tsize); | ||
256 | aead_tv = (void *)tvmem; | ||
257 | |||
258 | init_completion(&result.completion); | ||
259 | |||
260 | tfm = crypto_alloc_aead(algo, 0, 0); | ||
261 | |||
262 | if (IS_ERR(tfm)) { | ||
263 | printk(KERN_INFO "failed to load transform for %s: %ld\n", | ||
264 | algo, PTR_ERR(tfm)); | ||
265 | return; | ||
266 | } | ||
267 | |||
268 | req = aead_request_alloc(tfm, GFP_KERNEL); | ||
269 | if (!req) { | ||
270 | printk(KERN_INFO "failed to allocate request for %s\n", algo); | ||
271 | goto out; | ||
272 | } | ||
273 | |||
274 | aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | ||
275 | tcrypt_complete, &result); | ||
276 | |||
277 | for (i = 0, j = 0; i < tcount; i++) { | ||
278 | if (!aead_tv[i].np) { | ||
279 | printk(KERN_INFO "test %u (%d bit key):\n", | ||
280 | ++j, aead_tv[i].klen * 8); | ||
281 | |||
282 | crypto_aead_clear_flags(tfm, ~0); | ||
283 | if (aead_tv[i].wk) | ||
284 | crypto_aead_set_flags( | ||
285 | tfm, CRYPTO_TFM_REQ_WEAK_KEY); | ||
286 | key = aead_tv[i].key; | ||
287 | |||
288 | ret = crypto_aead_setkey(tfm, key, | ||
289 | aead_tv[i].klen); | ||
290 | if (ret) { | ||
291 | printk(KERN_INFO "setkey() failed flags=%x\n", | ||
292 | crypto_aead_get_flags(tfm)); | ||
293 | |||
294 | if (!aead_tv[i].fail) | ||
295 | goto out; | ||
296 | } | ||
297 | |||
298 | sg_init_one(&sg[0], aead_tv[i].input, | ||
299 | aead_tv[i].ilen); | ||
300 | |||
301 | sg_init_one(&asg[0], aead_tv[i].assoc, | ||
302 | aead_tv[i].alen); | ||
303 | |||
304 | aead_request_set_crypt(req, sg, sg, | ||
305 | aead_tv[i].ilen, | ||
306 | aead_tv[i].iv); | ||
307 | |||
308 | aead_request_set_assoc(req, asg, aead_tv[i].alen); | ||
309 | |||
310 | if (enc) { | ||
311 | ret = crypto_aead_encrypt(req); | ||
312 | } else { | ||
313 | memcpy(req->__ctx, aead_tv[i].tag, | ||
314 | aead_tv[i].tlen); | ||
315 | ret = crypto_aead_decrypt(req); | ||
316 | } | ||
317 | |||
318 | switch (ret) { | ||
319 | case 0: | ||
320 | break; | ||
321 | case -EINPROGRESS: | ||
322 | case -EBUSY: | ||
323 | ret = wait_for_completion_interruptible( | ||
324 | &result.completion); | ||
325 | if (!ret && !(ret = result.err)) { | ||
326 | INIT_COMPLETION(result.completion); | ||
327 | break; | ||
328 | } | ||
329 | /* fall through */ | ||
330 | default: | ||
331 | printk(KERN_INFO "%s () failed err=%d\n", | ||
332 | e, -ret); | ||
333 | goto out; | ||
334 | } | ||
335 | |||
336 | q = kmap(sg_page(&sg[0])) + sg[0].offset; | ||
337 | hexdump(q, aead_tv[i].rlen); | ||
338 | printk(KERN_INFO "auth tag: "); | ||
339 | hexdump((unsigned char *)req->__ctx, aead_tv[i].tlen); | ||
340 | |||
341 | printk(KERN_INFO "enc/dec: %s\n", | ||
342 | memcmp(q, aead_tv[i].result, | ||
343 | aead_tv[i].rlen) ? "fail" : "pass"); | ||
344 | |||
345 | printk(KERN_INFO "auth tag: %s\n", | ||
346 | memcmp(req->__ctx, aead_tv[i].tag, | ||
347 | aead_tv[i].tlen) ? "fail" : "pass"); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e); | ||
352 | memset(xbuf, 0, XBUFSIZE); | ||
353 | |||
354 | for (i = 0, j = 0; i < tcount; i++) { | ||
355 | if (aead_tv[i].np) { | ||
356 | printk(KERN_INFO "test %u (%d bit key):\n", | ||
357 | ++j, aead_tv[i].klen * 8); | ||
358 | |||
359 | crypto_aead_clear_flags(tfm, ~0); | ||
360 | if (aead_tv[i].wk) | ||
361 | crypto_aead_set_flags( | ||
362 | tfm, CRYPTO_TFM_REQ_WEAK_KEY); | ||
363 | key = aead_tv[i].key; | ||
364 | |||
365 | ret = crypto_aead_setkey(tfm, key, aead_tv[i].klen); | ||
366 | if (ret) { | ||
367 | printk(KERN_INFO "setkey() failed flags=%x\n", | ||
368 | crypto_aead_get_flags(tfm)); | ||
369 | |||
370 | if (!aead_tv[i].fail) | ||
371 | goto out; | ||
372 | } | ||
373 | |||
374 | sg_init_table(sg, aead_tv[i].np); | ||
375 | for (k = 0, temp = 0; k < aead_tv[i].np; k++) { | ||
376 | memcpy(&xbuf[IDX[k]], | ||
377 | aead_tv[i].input + temp, | ||
378 | aead_tv[i].tap[k]); | ||
379 | temp += aead_tv[i].tap[k]; | ||
380 | sg_set_buf(&sg[k], &xbuf[IDX[k]], | ||
381 | aead_tv[i].tap[k]); | ||
382 | } | ||
383 | |||
384 | sg_init_table(asg, aead_tv[i].anp); | ||
385 | for (k = 0, temp = 0; k < aead_tv[i].anp; k++) { | ||
386 | memcpy(&axbuf[IDX[k]], | ||
387 | aead_tv[i].assoc + temp, | ||
388 | aead_tv[i].atap[k]); | ||
389 | temp += aead_tv[i].atap[k]; | ||
390 | sg_set_buf(&asg[k], &axbuf[IDX[k]], | ||
391 | aead_tv[i].atap[k]); | ||
392 | } | ||
393 | |||
394 | aead_request_set_crypt(req, sg, sg, | ||
395 | aead_tv[i].ilen, | ||
396 | aead_tv[i].iv); | ||
397 | |||
398 | aead_request_set_assoc(req, asg, aead_tv[i].alen); | ||
399 | |||
400 | if (enc) { | ||
401 | ret = crypto_aead_encrypt(req); | ||
402 | } else { | ||
403 | memcpy(req->__ctx, aead_tv[i].tag, | ||
404 | aead_tv[i].tlen); | ||
405 | ret = crypto_aead_decrypt(req); | ||
406 | } | ||
407 | |||
408 | switch (ret) { | ||
409 | case 0: | ||
410 | break; | ||
411 | case -EINPROGRESS: | ||
412 | case -EBUSY: | ||
413 | ret = wait_for_completion_interruptible( | ||
414 | &result.completion); | ||
415 | if (!ret && !(ret = result.err)) { | ||
416 | INIT_COMPLETION(result.completion); | ||
417 | break; | ||
418 | } | ||
419 | /* fall through */ | ||
420 | default: | ||
421 | printk(KERN_INFO "%s () failed err=%d\n", | ||
422 | e, -ret); | ||
423 | goto out; | ||
424 | } | ||
425 | |||
426 | for (k = 0, temp = 0; k < aead_tv[i].np; k++) { | ||
427 | printk(KERN_INFO "page %u\n", k); | ||
428 | q = kmap(sg_page(&sg[k])) + sg[k].offset; | ||
429 | hexdump(q, aead_tv[i].tap[k]); | ||
430 | printk(KERN_INFO "%s\n", | ||
431 | memcmp(q, aead_tv[i].result + temp, | ||
432 | aead_tv[i].tap[k]) ? | ||
433 | "fail" : "pass"); | ||
434 | |||
435 | temp += aead_tv[i].tap[k]; | ||
436 | } | ||
437 | printk(KERN_INFO "auth tag: "); | ||
438 | hexdump((unsigned char *)req->__ctx, aead_tv[i].tlen); | ||
439 | |||
440 | printk(KERN_INFO "auth tag: %s\n", | ||
441 | memcmp(req->__ctx, aead_tv[i].tag, | ||
442 | aead_tv[i].tlen) ? "fail" : "pass"); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | out: | ||
447 | crypto_free_aead(tfm); | ||
448 | aead_request_free(req); | ||
449 | } | ||
450 | |||
220 | static void test_cipher(char *algo, int enc, | 451 | static void test_cipher(char *algo, int enc, |
221 | struct cipher_testvec *template, unsigned int tcount) | 452 | struct cipher_testvec *template, unsigned int tcount) |
222 | { | 453 | { |
@@ -1497,20 +1728,21 @@ static void do_test(void) | |||
1497 | 1728 | ||
1498 | static int __init init(void) | 1729 | static int __init init(void) |
1499 | { | 1730 | { |
1731 | int err = -ENOMEM; | ||
1732 | |||
1500 | tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL); | 1733 | tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL); |
1501 | if (tvmem == NULL) | 1734 | if (tvmem == NULL) |
1502 | return -ENOMEM; | 1735 | return err; |
1503 | 1736 | ||
1504 | xbuf = kmalloc(XBUFSIZE, GFP_KERNEL); | 1737 | xbuf = kmalloc(XBUFSIZE, GFP_KERNEL); |
1505 | if (xbuf == NULL) { | 1738 | if (xbuf == NULL) |
1506 | kfree(tvmem); | 1739 | goto err_free_tv; |
1507 | return -ENOMEM; | ||
1508 | } | ||
1509 | 1740 | ||
1510 | do_test(); | 1741 | axbuf = kmalloc(XBUFSIZE, GFP_KERNEL); |
1742 | if (axbuf == NULL) | ||
1743 | goto err_free_xbuf; | ||
1511 | 1744 | ||
1512 | kfree(xbuf); | 1745 | do_test(); |
1513 | kfree(tvmem); | ||
1514 | 1746 | ||
1515 | /* We intentionaly return -EAGAIN to prevent keeping | 1747 | /* We intentionaly return -EAGAIN to prevent keeping |
1516 | * the module. It does all its work from init() | 1748 | * the module. It does all its work from init() |
@@ -1518,7 +1750,15 @@ static int __init init(void) | |||
1518 | * => we don't need it in the memory, do we? | 1750 | * => we don't need it in the memory, do we? |
1519 | * -- mludvig | 1751 | * -- mludvig |
1520 | */ | 1752 | */ |
1521 | return -EAGAIN; | 1753 | err = -EAGAIN; |
1754 | |||
1755 | kfree(axbuf); | ||
1756 | err_free_xbuf: | ||
1757 | kfree(xbuf); | ||
1758 | err_free_tv: | ||
1759 | kfree(tvmem); | ||
1760 | |||
1761 | return err; | ||
1522 | } | 1762 | } |
1523 | 1763 | ||
1524 | /* | 1764 | /* |
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index 6ffc411bf464..865196a648a0 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h | |||
@@ -6,12 +6,14 @@ | |||
6 | * | 6 | * |
7 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> | 7 | * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> |
8 | * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> | 8 | * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> |
9 | * Copyright (c) 2007 Nokia Siemens Networks | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the Free | 12 | * under the terms of the GNU General Public License as published by the Free |
12 | * Software Foundation; either version 2 of the License, or (at your option) | 13 | * Software Foundation; either version 2 of the License, or (at your option) |
13 | * any later version. | 14 | * any later version. |
14 | * | 15 | * |
16 | * 2007-11-13 Added AEAD support | ||
15 | * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests | 17 | * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests |
16 | * 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net> | 18 | * 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net> |
17 | * 2003-09-14 Changes by Kartikey Mahendra Bhatt | 19 | * 2003-09-14 Changes by Kartikey Mahendra Bhatt |
@@ -51,6 +53,26 @@ struct cipher_testvec { | |||
51 | unsigned short rlen; | 53 | unsigned short rlen; |
52 | }; | 54 | }; |
53 | 55 | ||
56 | struct aead_testvec { | ||
57 | char key[MAX_KEYLEN] __attribute__ ((__aligned__(4))); | ||
58 | char iv[MAX_IVLEN]; | ||
59 | char input[512]; | ||
60 | char assoc[512]; | ||
61 | char result[512]; | ||
62 | char tag[128]; | ||
63 | unsigned char tap[MAX_TAP]; | ||
64 | unsigned char atap[MAX_TAP]; | ||
65 | int np; | ||
66 | int anp; | ||
67 | unsigned char fail; | ||
68 | unsigned char wk; /* weak key flag */ | ||
69 | unsigned char klen; | ||
70 | unsigned short ilen; | ||
71 | unsigned short alen; | ||
72 | unsigned short rlen; | ||
73 | unsigned short tlen; | ||
74 | }; | ||
75 | |||
54 | struct cipher_speed { | 76 | struct cipher_speed { |
55 | unsigned char klen; | 77 | unsigned char klen; |
56 | unsigned int blen; | 78 | unsigned int blen; |