|
@@ -6,12 +6,14 @@
|
|
|
*
|
|
|
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
|
|
|
* Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
|
|
|
+ * Copyright (c) 2007 Nokia Siemens Networks
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
* any later version.
|
|
|
*
|
|
|
+ * 2007-11-13 Added AEAD support
|
|
|
* 2007-11-06 Added SHA-224 and SHA-224-HMAC tests
|
|
|
* 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
|
|
|
* 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
|
|
@@ -72,6 +74,7 @@ static unsigned int sec;
|
|
|
|
|
|
static int mode;
|
|
|
static char *xbuf;
|
|
|
+static char *axbuf;
|
|
|
static char *tvmem;
|
|
|
|
|
|
static char *check[] = {
|
|
@@ -169,6 +172,7 @@ static void test_hash(char *algo, struct hash_testvec *template,
|
|
|
|
|
|
/* setup the dummy buffer first */
|
|
|
memset(xbuf, 0, XBUFSIZE);
|
|
|
+ memset(axbuf, 0, XBUFSIZE);
|
|
|
|
|
|
j = 0;
|
|
|
for (i = 0; i < tcount; i++) {
|
|
@@ -217,6 +221,233 @@ out:
|
|
|
crypto_free_hash(tfm);
|
|
|
}
|
|
|
|
|
|
+static void test_aead(char *algo, int enc, struct aead_testvec *template,
|
|
|
+ unsigned int tcount)
|
|
|
+{
|
|
|
+ unsigned int ret, i, j, k, temp;
|
|
|
+ unsigned int tsize;
|
|
|
+ char *q;
|
|
|
+ struct crypto_aead *tfm;
|
|
|
+ char *key;
|
|
|
+ struct aead_testvec *aead_tv;
|
|
|
+ struct aead_request *req;
|
|
|
+ struct scatterlist sg[8];
|
|
|
+ struct scatterlist asg[8];
|
|
|
+ const char *e;
|
|
|
+ struct tcrypt_result result;
|
|
|
+
|
|
|
+ if (enc == ENCRYPT)
|
|
|
+ e = "encryption";
|
|
|
+ else
|
|
|
+ e = "decryption";
|
|
|
+
|
|
|
+ printk(KERN_INFO "\ntesting %s %s\n", algo, e);
|
|
|
+
|
|
|
+ tsize = sizeof(struct aead_testvec);
|
|
|
+ tsize *= tcount;
|
|
|
+
|
|
|
+ if (tsize > TVMEMSIZE) {
|
|
|
+ printk(KERN_INFO "template (%u) too big for tvmem (%u)\n",
|
|
|
+ tsize, TVMEMSIZE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(tvmem, template, tsize);
|
|
|
+ aead_tv = (void *)tvmem;
|
|
|
+
|
|
|
+ init_completion(&result.completion);
|
|
|
+
|
|
|
+ tfm = crypto_alloc_aead(algo, 0, 0);
|
|
|
+
|
|
|
+ if (IS_ERR(tfm)) {
|
|
|
+ printk(KERN_INFO "failed to load transform for %s: %ld\n",
|
|
|
+ algo, PTR_ERR(tfm));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ req = aead_request_alloc(tfm, GFP_KERNEL);
|
|
|
+ if (!req) {
|
|
|
+ printk(KERN_INFO "failed to allocate request for %s\n", algo);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
|
|
+ tcrypt_complete, &result);
|
|
|
+
|
|
|
+ for (i = 0, j = 0; i < tcount; i++) {
|
|
|
+ if (!aead_tv[i].np) {
|
|
|
+ printk(KERN_INFO "test %u (%d bit key):\n",
|
|
|
+ ++j, aead_tv[i].klen * 8);
|
|
|
+
|
|
|
+ crypto_aead_clear_flags(tfm, ~0);
|
|
|
+ if (aead_tv[i].wk)
|
|
|
+ crypto_aead_set_flags(
|
|
|
+ tfm, CRYPTO_TFM_REQ_WEAK_KEY);
|
|
|
+ key = aead_tv[i].key;
|
|
|
+
|
|
|
+ ret = crypto_aead_setkey(tfm, key,
|
|
|
+ aead_tv[i].klen);
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_INFO "setkey() failed flags=%x\n",
|
|
|
+ crypto_aead_get_flags(tfm));
|
|
|
+
|
|
|
+ if (!aead_tv[i].fail)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ sg_init_one(&sg[0], aead_tv[i].input,
|
|
|
+ aead_tv[i].ilen);
|
|
|
+
|
|
|
+ sg_init_one(&asg[0], aead_tv[i].assoc,
|
|
|
+ aead_tv[i].alen);
|
|
|
+
|
|
|
+ aead_request_set_crypt(req, sg, sg,
|
|
|
+ aead_tv[i].ilen,
|
|
|
+ aead_tv[i].iv);
|
|
|
+
|
|
|
+ aead_request_set_assoc(req, asg, aead_tv[i].alen);
|
|
|
+
|
|
|
+ if (enc) {
|
|
|
+ ret = crypto_aead_encrypt(req);
|
|
|
+ } else {
|
|
|
+ memcpy(req->__ctx, aead_tv[i].tag,
|
|
|
+ aead_tv[i].tlen);
|
|
|
+ ret = crypto_aead_decrypt(req);
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (ret) {
|
|
|
+ case 0:
|
|
|
+ break;
|
|
|
+ case -EINPROGRESS:
|
|
|
+ case -EBUSY:
|
|
|
+ ret = wait_for_completion_interruptible(
|
|
|
+ &result.completion);
|
|
|
+ if (!ret && !(ret = result.err)) {
|
|
|
+ INIT_COMPLETION(result.completion);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* fall through */
|
|
|
+ default:
|
|
|
+ printk(KERN_INFO "%s () failed err=%d\n",
|
|
|
+ e, -ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ q = kmap(sg_page(&sg[0])) + sg[0].offset;
|
|
|
+ hexdump(q, aead_tv[i].rlen);
|
|
|
+ printk(KERN_INFO "auth tag: ");
|
|
|
+ hexdump((unsigned char *)req->__ctx, aead_tv[i].tlen);
|
|
|
+
|
|
|
+ printk(KERN_INFO "enc/dec: %s\n",
|
|
|
+ memcmp(q, aead_tv[i].result,
|
|
|
+ aead_tv[i].rlen) ? "fail" : "pass");
|
|
|
+
|
|
|
+ printk(KERN_INFO "auth tag: %s\n",
|
|
|
+ memcmp(req->__ctx, aead_tv[i].tag,
|
|
|
+ aead_tv[i].tlen) ? "fail" : "pass");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
|
|
|
+ memset(xbuf, 0, XBUFSIZE);
|
|
|
+
|
|
|
+ for (i = 0, j = 0; i < tcount; i++) {
|
|
|
+ if (aead_tv[i].np) {
|
|
|
+ printk(KERN_INFO "test %u (%d bit key):\n",
|
|
|
+ ++j, aead_tv[i].klen * 8);
|
|
|
+
|
|
|
+ crypto_aead_clear_flags(tfm, ~0);
|
|
|
+ if (aead_tv[i].wk)
|
|
|
+ crypto_aead_set_flags(
|
|
|
+ tfm, CRYPTO_TFM_REQ_WEAK_KEY);
|
|
|
+ key = aead_tv[i].key;
|
|
|
+
|
|
|
+ ret = crypto_aead_setkey(tfm, key, aead_tv[i].klen);
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_INFO "setkey() failed flags=%x\n",
|
|
|
+ crypto_aead_get_flags(tfm));
|
|
|
+
|
|
|
+ if (!aead_tv[i].fail)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ sg_init_table(sg, aead_tv[i].np);
|
|
|
+ for (k = 0, temp = 0; k < aead_tv[i].np; k++) {
|
|
|
+ memcpy(&xbuf[IDX[k]],
|
|
|
+ aead_tv[i].input + temp,
|
|
|
+ aead_tv[i].tap[k]);
|
|
|
+ temp += aead_tv[i].tap[k];
|
|
|
+ sg_set_buf(&sg[k], &xbuf[IDX[k]],
|
|
|
+ aead_tv[i].tap[k]);
|
|
|
+ }
|
|
|
+
|
|
|
+ sg_init_table(asg, aead_tv[i].anp);
|
|
|
+ for (k = 0, temp = 0; k < aead_tv[i].anp; k++) {
|
|
|
+ memcpy(&axbuf[IDX[k]],
|
|
|
+ aead_tv[i].assoc + temp,
|
|
|
+ aead_tv[i].atap[k]);
|
|
|
+ temp += aead_tv[i].atap[k];
|
|
|
+ sg_set_buf(&asg[k], &axbuf[IDX[k]],
|
|
|
+ aead_tv[i].atap[k]);
|
|
|
+ }
|
|
|
+
|
|
|
+ aead_request_set_crypt(req, sg, sg,
|
|
|
+ aead_tv[i].ilen,
|
|
|
+ aead_tv[i].iv);
|
|
|
+
|
|
|
+ aead_request_set_assoc(req, asg, aead_tv[i].alen);
|
|
|
+
|
|
|
+ if (enc) {
|
|
|
+ ret = crypto_aead_encrypt(req);
|
|
|
+ } else {
|
|
|
+ memcpy(req->__ctx, aead_tv[i].tag,
|
|
|
+ aead_tv[i].tlen);
|
|
|
+ ret = crypto_aead_decrypt(req);
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (ret) {
|
|
|
+ case 0:
|
|
|
+ break;
|
|
|
+ case -EINPROGRESS:
|
|
|
+ case -EBUSY:
|
|
|
+ ret = wait_for_completion_interruptible(
|
|
|
+ &result.completion);
|
|
|
+ if (!ret && !(ret = result.err)) {
|
|
|
+ INIT_COMPLETION(result.completion);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* fall through */
|
|
|
+ default:
|
|
|
+ printk(KERN_INFO "%s () failed err=%d\n",
|
|
|
+ e, -ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (k = 0, temp = 0; k < aead_tv[i].np; k++) {
|
|
|
+ printk(KERN_INFO "page %u\n", k);
|
|
|
+ q = kmap(sg_page(&sg[k])) + sg[k].offset;
|
|
|
+ hexdump(q, aead_tv[i].tap[k]);
|
|
|
+ printk(KERN_INFO "%s\n",
|
|
|
+ memcmp(q, aead_tv[i].result + temp,
|
|
|
+ aead_tv[i].tap[k]) ?
|
|
|
+ "fail" : "pass");
|
|
|
+
|
|
|
+ temp += aead_tv[i].tap[k];
|
|
|
+ }
|
|
|
+ printk(KERN_INFO "auth tag: ");
|
|
|
+ hexdump((unsigned char *)req->__ctx, aead_tv[i].tlen);
|
|
|
+
|
|
|
+ printk(KERN_INFO "auth tag: %s\n",
|
|
|
+ memcmp(req->__ctx, aead_tv[i].tag,
|
|
|
+ aead_tv[i].tlen) ? "fail" : "pass");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ crypto_free_aead(tfm);
|
|
|
+ aead_request_free(req);
|
|
|
+}
|
|
|
+
|
|
|
static void test_cipher(char *algo, int enc,
|
|
|
struct cipher_testvec *template, unsigned int tcount)
|
|
|
{
|
|
@@ -1497,20 +1728,21 @@ static void do_test(void)
|
|
|
|
|
|
static int __init init(void)
|
|
|
{
|
|
|
+ int err = -ENOMEM;
|
|
|
+
|
|
|
tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL);
|
|
|
if (tvmem == NULL)
|
|
|
- return -ENOMEM;
|
|
|
+ return err;
|
|
|
|
|
|
xbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
|
|
|
- if (xbuf == NULL) {
|
|
|
- kfree(tvmem);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
+ if (xbuf == NULL)
|
|
|
+ goto err_free_tv;
|
|
|
|
|
|
- do_test();
|
|
|
+ axbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
|
|
|
+ if (axbuf == NULL)
|
|
|
+ goto err_free_xbuf;
|
|
|
|
|
|
- kfree(xbuf);
|
|
|
- kfree(tvmem);
|
|
|
+ do_test();
|
|
|
|
|
|
/* We intentionaly return -EAGAIN to prevent keeping
|
|
|
* the module. It does all its work from init()
|
|
@@ -1518,7 +1750,15 @@ static int __init init(void)
|
|
|
* => we don't need it in the memory, do we?
|
|
|
* -- mludvig
|
|
|
*/
|
|
|
- return -EAGAIN;
|
|
|
+ err = -EAGAIN;
|
|
|
+
|
|
|
+ kfree(axbuf);
|
|
|
+ err_free_xbuf:
|
|
|
+ kfree(xbuf);
|
|
|
+ err_free_tv:
|
|
|
+ kfree(tvmem);
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/*
|