Skip to content

Commit

Permalink
[CRYPTO] tcrypt: Add aead support
Browse files Browse the repository at this point in the history
Add AEAD support to tcrypt, needed by GCM.

Signed-off-by: Mikko Herranen <[email protected]>
Reviewed-by: Mika Kukkonen <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
Mikko Herranen authored and herbertx committed Jan 10, 2008
1 parent ff85a80 commit e3a4ea4
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 9 deletions.
258 changes: 249 additions & 9 deletions crypto/tcrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
*
* Copyright (c) 2002 James Morris <[email protected]>
* Copyright (c) 2002 Jean-Francois Dive <[email protected]>
* 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 <[email protected]>)
Expand Down Expand Up @@ -72,6 +74,7 @@ static unsigned int sec;

static int mode;
static char *xbuf;
static char *axbuf;
static char *tvmem;

static char *check[] = {
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -217,6 +221,233 @@ static void test_hash(char *algo, struct hash_testvec *template,
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)
{
Expand Down Expand Up @@ -1497,28 +1728,37 @@ 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()
* and doesn't offer any runtime functionality
* => 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;
}

/*
Expand Down
22 changes: 22 additions & 0 deletions crypto/tcrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
*
* Copyright (c) 2002 James Morris <[email protected]>
* Copyright (c) 2002 Jean-Francois Dive <[email protected]>
* 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
* 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
* 2004-08-09 Cipher speed tests by Reyk Floeter <[email protected]>
* 2003-09-14 Changes by Kartikey Mahendra Bhatt
Expand Down Expand Up @@ -51,6 +53,26 @@ struct cipher_testvec {
unsigned short rlen;
};

struct aead_testvec {
char key[MAX_KEYLEN] __attribute__ ((__aligned__(4)));
char iv[MAX_IVLEN];
char input[512];
char assoc[512];
char result[512];
char tag[128];
unsigned char tap[MAX_TAP];
unsigned char atap[MAX_TAP];
int np;
int anp;
unsigned char fail;
unsigned char wk; /* weak key flag */
unsigned char klen;
unsigned short ilen;
unsigned short alen;
unsigned short rlen;
unsigned short tlen;
};

struct cipher_speed {
unsigned char klen;
unsigned int blen;
Expand Down

0 comments on commit e3a4ea4

Please sign in to comment.