diff options
author | James Morris <jmorris@intercode.com.au> | 2002-11-03 10:13:19 -0800 |
---|---|---|
committer | David S. Miller <davem@nuts.ninka.net> | 2002-11-03 10:13:19 -0800 |
commit | 464ff46093bd6ed4da11037edda18378b6804c1a (patch) | |
tree | 1b3f983799bb2249759c43c4ace3eb4bf6a55d12 /crypto | |
parent | 03d4a1cd25137f70857cc524548cb6b34371cce6 (diff) | |
download | history-464ff46093bd6ed4da11037edda18378b6804c1a.tar.gz |
[CRYPTO]: Rework HMAC interface.
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 14 | ||||
-rw-r--r-- | crypto/Makefile | 3 | ||||
-rw-r--r-- | crypto/digest.c | 62 | ||||
-rw-r--r-- | crypto/hmac.c | 112 | ||||
-rw-r--r-- | crypto/tcrypt.c | 189 | ||||
-rw-r--r-- | crypto/tcrypt.h | 30 |
6 files changed, 278 insertions, 132 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index b3337e230554ca..f30a0c1fee2ef6 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -9,24 +9,30 @@ config CRYPTO help This option provides the core Cryptographic API. +config CRYPTO_HMAC + bool "HMAC support" + depends on CRYPTO + help + HMAC: Keyed-Hashing for Message Authentication (RFC2104). + This is required for IPSec. + config CRYPTO_MD4 tristate "MD4 digest algorithm" depends on CRYPTO help - MD4 message digest algorithm (RFC1320), including HMAC (RFC2104). - + MD4 message digest algorithm (RFC1320). config CRYPTO_MD5 tristate "MD5 digest algorithm" depends on CRYPTO help - MD5 message digest algorithm (RFC1321), including HMAC (RFC2104, RFC2403). + MD5 message digest algorithm (RFC1321). config CRYPTO_SHA1 tristate "SHA-1 digest algorithm" depends on CRYPTO help - SHA-1 secure hash standard (FIPS 180-1), including HMAC (RFC2104, RFC2404). + SHA-1 secure hash standard (FIPS 180-1). config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" diff --git a/crypto/Makefile b/crypto/Makefile index a9eb930fcbd33e..658e55b1a4d128 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,11 +2,12 @@ # Cryptographic API # -export-objs := api.o +export-objs := api.o hmac.o obj-$(CONFIG_CRYPTO) += api.o cipher.o digest.o compress.o obj-$(CONFIG_KMOD) += autoload.o +obj-$(CONFIG_CRYPTO_HMAC) += hmac.o obj-$(CONFIG_CRYPTO_MD4) += md4.o obj-$(CONFIG_CRYPTO_MD5) += md5.o obj-$(CONFIG_CRYPTO_SHA1) += sha1.o diff --git a/crypto/digest.c b/crypto/digest.c index dde4deb1deed41..83aae1d9eaf7fc 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -5,9 +5,6 @@ * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * - * The HMAC implementation is derived from USAGI. - * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI - * * 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) @@ -61,56 +58,6 @@ static void digest(struct crypto_tfm *tfm, crypto_digest_final(tfm, out); } -static void hmac(struct crypto_tfm *tfm, u8 *key, unsigned int keylen, - struct scatterlist *sg, unsigned int nsg, u8 *out) -{ - unsigned int i; - struct scatterlist tmp; - char ipad[crypto_tfm_alg_blocksize(tfm) + 1]; - char opad[crypto_tfm_alg_blocksize(tfm) + 1]; - - if (keylen > crypto_tfm_alg_blocksize(tfm)) { - tmp.page = virt_to_page(key); - tmp.offset = ((long)key & ~PAGE_MASK); - tmp.length = keylen; - crypto_digest_digest(tfm, &tmp, 1, key); - keylen = crypto_tfm_alg_digestsize(tfm); - } - - memset(ipad, 0, sizeof(ipad)); - memset(opad, 0, sizeof(opad)); - memcpy(ipad, key, keylen); - memcpy(opad, key, keylen); - - for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - tmp.page = virt_to_page(ipad); - tmp.offset = ((long)ipad & ~PAGE_MASK); - tmp.length = crypto_tfm_alg_blocksize(tfm); - - crypto_digest_init(tfm); - crypto_digest_update(tfm, &tmp, 1); - crypto_digest_update(tfm, sg, nsg); - crypto_digest_final(tfm, out); - - tmp.page = virt_to_page(opad); - tmp.offset = ((long)opad & ~PAGE_MASK); - tmp.length = crypto_tfm_alg_blocksize(tfm); - - crypto_digest_init(tfm); - crypto_digest_update(tfm, &tmp, 1); - - tmp.page = virt_to_page(out); - tmp.offset = ((long)out & ~PAGE_MASK); - tmp.length = crypto_tfm_alg_digestsize(tfm); - - crypto_digest_update(tfm, &tmp, 1); - crypto_digest_final(tfm, out); -} - int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) { return crypto_cipher_flags(flags) ? -EINVAL : 0; @@ -120,9 +67,8 @@ void crypto_init_digest_ops(struct crypto_tfm *tfm) { struct digest_tfm *ops = &tfm->crt_digest; - ops->dit_init = init; - ops->dit_update = update; - ops->dit_final = final; - ops->dit_digest = digest; - ops->dit_hmac = hmac; + ops->dit_init = init; + ops->dit_update = update; + ops->dit_final = final; + ops->dit_digest = digest; } diff --git a/crypto/hmac.c b/crypto/hmac.c new file mode 100644 index 00000000000000..12876685373172 --- /dev/null +++ b/crypto/hmac.c @@ -0,0 +1,112 @@ +/* + * Cryptographic API. + * + * HMAC: Keyed-Hashing for Message Authentication (RFC2104). + * + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * + * The HMAC implementation is derived from USAGI. + * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI + * + * 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. + * + */ +#include <linux/crypto.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <asm/scatterlist.h> +#include "internal.h" + +static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen) +{ + struct scatterlist tmp; + + tmp.page = virt_to_page(key); + tmp.offset = ((long)key & ~PAGE_MASK); + tmp.length = keylen; + crypto_digest_digest(tfm, &tmp, 1, key); + +} + +void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen) +{ + unsigned int i; + struct scatterlist tmp; + char ipad[crypto_tfm_alg_blocksize(tfm) + 1]; + + if (*keylen > crypto_tfm_alg_blocksize(tfm)) { + hash_key(tfm, key, *keylen); + *keylen = crypto_tfm_alg_digestsize(tfm); + } + + memset(ipad, 0, sizeof(ipad)); + memcpy(ipad, key, *keylen); + + for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) + ipad[i] ^= 0x36; + + tmp.page = virt_to_page(ipad); + tmp.offset = ((long)ipad & ~PAGE_MASK); + tmp.length = crypto_tfm_alg_blocksize(tfm); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, &tmp, 1); +} + +void crypto_hmac_update(struct crypto_tfm *tfm, + struct scatterlist *sg, unsigned int nsg) +{ + crypto_digest_update(tfm, sg, nsg); +} + +void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, + unsigned int *keylen, u8 *out) +{ + unsigned int i; + struct scatterlist tmp; + char opad[crypto_tfm_alg_blocksize(tfm) + 1]; + + if (*keylen > crypto_tfm_alg_blocksize(tfm)) { + hash_key(tfm, key, *keylen); + *keylen = crypto_tfm_alg_digestsize(tfm); + } + + crypto_digest_final(tfm, out); + + memset(opad, 0, sizeof(opad)); + memcpy(opad, key, *keylen); + + for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) + opad[i] ^= 0x5c; + + tmp.page = virt_to_page(opad); + tmp.offset = ((long)opad & ~PAGE_MASK); + tmp.length = crypto_tfm_alg_blocksize(tfm); + + crypto_digest_init(tfm); + crypto_digest_update(tfm, &tmp, 1); + + tmp.page = virt_to_page(out); + tmp.offset = ((long)out & ~PAGE_MASK); + tmp.length = crypto_tfm_alg_digestsize(tfm); + + crypto_digest_update(tfm, &tmp, 1); + crypto_digest_final(tfm, out); +} + +void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, + struct scatterlist *sg, unsigned int nsg, u8 *out) +{ + crypto_hmac_init(tfm, key, keylen); + crypto_hmac_update(tfm, sg, nsg); + crypto_hmac_final(tfm, key, keylen, out); +} + +EXPORT_SYMBOL_GPL(crypto_hmac_init); +EXPORT_SYMBOL_GPL(crypto_hmac_update); +EXPORT_SYMBOL_GPL(crypto_hmac_final); +EXPORT_SYMBOL_GPL(crypto_hmac); + diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index fd284ee8836cdf..50b8a6f4dc4764 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -66,7 +66,6 @@ test_md5(void) char result[128]; struct crypto_tfm *tfm; struct md5_testvec *md5_tv; - struct hmac_md5_testvec *hmac_md5_tv; unsigned int tsize; printk("\ntesting md5\n"); @@ -131,14 +130,34 @@ test_md5(void) printk("%s\n", memcmp(result, md5_tv[4].digest, crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); + crypto_free_tfm(tfm); +} - printk("\ntesting hmac_md5\n"); +#ifdef CONFIG_CRYPTO_HMAC +static void +test_hmac_md5(void) +{ + char *p; + unsigned int i, klen; + struct scatterlist sg[2]; + char result[128]; + struct crypto_tfm *tfm; + struct hmac_md5_testvec *hmac_md5_tv; + unsigned int tsize; + tfm = crypto_alloc_tfm("md5", 0); + if (tfm == NULL) { + printk("failed to load transform for md5\n"); + return; + } + + printk("\ntesting hmac_md5\n"); + tsize = sizeof (hmac_md5_tv_template); if (tsize > TVMEMSIZE) { printk("template (%u) too big for tvmem (%u)\n", tsize, TVMEMSIZE); - return; + goto out; } memcpy(tvmem, hmac_md5_tv_template, tsize); @@ -153,8 +172,8 @@ test_md5(void) sg[0].offset = ((long) p & ~PAGE_MASK); sg[0].length = strlen(hmac_md5_tv[i].plaintext); - crypto_digest_hmac(tfm, hmac_md5_tv[i].key, - strlen(hmac_md5_tv[i].key), sg, 1, result); + klen = strlen(hmac_md5_tv[i].key); + crypto_hmac(tfm, hmac_md5_tv[i].key, &klen, sg, 1, result); hexdump(result, crypto_tfm_alg_digestsize(tfm)); printk("%s\n", @@ -181,16 +200,96 @@ test_md5(void) sg[1].length = 12; memset(result, 0, sizeof (result)); - crypto_digest_hmac(tfm, hmac_md5_tv[1].key, strlen(hmac_md5_tv[1].key), - sg, 2, result); + klen = strlen(hmac_md5_tv[7].key); + crypto_hmac(tfm, hmac_md5_tv[7].key, &klen, sg, 2, result); hexdump(result, crypto_tfm_alg_digestsize(tfm)); printk("%s\n", - memcmp(result, hmac_md5_tv[1].digest, + memcmp(result, hmac_md5_tv[7].digest, crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); +out: + crypto_free_tfm(tfm); +} + +static void +test_hmac_sha1(void) +{ + char *p; + unsigned int i, klen; + struct crypto_tfm *tfm; + struct hmac_sha1_testvec *hmac_sha1_tv; + struct scatterlist sg[2]; + unsigned int tsize; + char result[SHA1_DIGEST_SIZE]; + + tfm = crypto_alloc_tfm("sha1", 0); + if (tfm == NULL) { + printk("failed to load transform for sha1\n"); + return; + } + + printk("\ntesting hmac_sha1\n"); + + tsize = sizeof (hmac_sha1_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, hmac_sha1_tv_template, tsize); + hmac_sha1_tv = (void *) tvmem; + + for (i = 0; i < HMAC_SHA1_TEST_VECTORS; i++) { + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + p = hmac_sha1_tv[i].plaintext; + sg[0].page = virt_to_page(p); + sg[0].offset = ((long) p & ~PAGE_MASK); + sg[0].length = strlen(hmac_sha1_tv[i].plaintext); + + klen = strlen(hmac_sha1_tv[i].key); + + crypto_hmac(tfm, hmac_sha1_tv[i].key, &klen, sg, 1, result); + hexdump(result, sizeof (result)); + printk("%s\n", + memcmp(result, hmac_sha1_tv[i].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : + "pass"); + } + + printk("\ntesting hmac_sha1 across pages\n"); + + /* setup the dummy buffer first */ + memset(xbuf, 0, sizeof (xbuf)); + + memcpy(&xbuf[IDX1], "what do ya want ", 16); + memcpy(&xbuf[IDX2], "for nothing?", 12); + + p = &xbuf[IDX1]; + sg[0].page = virt_to_page(p); + sg[0].offset = ((long) p & ~PAGE_MASK); + sg[0].length = 16; + + p = &xbuf[IDX2]; + sg[1].page = virt_to_page(p); + sg[1].offset = ((long) p & ~PAGE_MASK); + sg[1].length = 12; + + memset(result, 0, sizeof (result)); + klen = strlen(hmac_sha1_tv[7].key); + crypto_hmac(tfm, hmac_sha1_tv[7].key, &klen, sg, 2, result); + hexdump(result, crypto_tfm_alg_digestsize(tfm)); + + printk("%s\n", + memcmp(result, hmac_sha1_tv[7].digest, + crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); +out: crypto_free_tfm(tfm); } +#endif /* CONFIG_CRYPTO_HMAC */ static void test_md4(void) @@ -249,7 +348,6 @@ test_sha1(void) unsigned int i; struct crypto_tfm *tfm; struct sha1_testvec *sha1_tv; - struct hmac_sha1_testvec *hmac_sha1_tv; struct scatterlist sg[2]; unsigned int tsize; char result[SHA1_DIGEST_SIZE]; @@ -315,64 +413,6 @@ test_sha1(void) printk("%s\n", memcmp(result, sha1_tv[1].digest, crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); - - printk("\ntesting hmac_sha1\n"); - - tsize = sizeof (hmac_sha1_tv_template); - if (tsize > TVMEMSIZE) { - printk("template (%u) too big for tvmem (%u)\n", tsize, - TVMEMSIZE); - return; - } - - memcpy(tvmem, hmac_sha1_tv_template, tsize); - hmac_sha1_tv = (void *) tvmem; - - for (i = 0; i < HMAC_SHA1_TEST_VECTORS; i++) { - printk("test %u:\n", i + 1); - memset(result, 0, sizeof (result)); - - p = hmac_sha1_tv[i].plaintext; - sg[0].page = virt_to_page(p); - sg[0].offset = ((long) p & ~PAGE_MASK); - sg[0].length = strlen(hmac_sha1_tv[i].plaintext); - - crypto_digest_hmac(tfm, hmac_sha1_tv[i].key, - strlen(hmac_sha1_tv[i].key), sg, 1, result); - - hexdump(result, sizeof (result)); - printk("%s\n", - memcmp(result, hmac_sha1_tv[i].digest, - crypto_tfm_alg_digestsize(tfm)) ? "fail" : - "pass"); - } - - printk("\ntesting hmac_sha1 across pages\n"); - - /* setup the dummy buffer first */ - memset(xbuf, 0, sizeof (xbuf)); - - memcpy(&xbuf[IDX1], "what do ya want ", 16); - memcpy(&xbuf[IDX2], "for nothing?", 12); - - p = &xbuf[IDX1]; - sg[0].page = virt_to_page(p); - sg[0].offset = ((long) p & ~PAGE_MASK); - sg[0].length = 16; - - p = &xbuf[IDX2]; - sg[1].page = virt_to_page(p); - sg[1].offset = ((long) p & ~PAGE_MASK); - sg[1].length = 12; - - memset(result, 0, sizeof (result)); - crypto_digest_hmac(tfm, hmac_sha1_tv[1].key, - strlen(hmac_sha1_tv[1].key), sg, 2, result); - hexdump(result, crypto_tfm_alg_digestsize(tfm)); - - printk("%s\n", - memcmp(result, hmac_sha1_tv[1].digest, - crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass"); crypto_free_tfm(tfm); } @@ -1325,6 +1365,10 @@ do_test(void) test_des(); test_des3_ede(); test_md4(); +#ifdef CONFIG_CRYPTO_HMAC + test_hmac_md5(); + test_hmac_sha1(); +#endif break; case 1: @@ -1347,7 +1391,18 @@ do_test(void) test_md4(); break; +#ifdef CONFIG_CRYPTO_HMAC case 100: + test_hmac_md5(); + break; + + + case 101: + test_hmac_sha1(); + break; +#endif + + case 1000: test_available(); break; diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index d6ab3149367da9..a158063c5060b4 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -105,6 +105,7 @@ struct md5_testvec { 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } } }; +#ifdef CONFIG_CRYPTO_HMAC /* * HMAC-MD5 test vectors from RFC2202 * (These need to be fixed to not use strlen). @@ -214,7 +215,19 @@ struct hmac_md5_testvec hmac_md5_tv_template[] = { 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e } - } + }, + + /* cross page test, need to retain key */ + + { + { 'J', 'e', 'f', 'e', 0 }, + + "what do ya want for nothing?", + + { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 } + }, + }; @@ -334,9 +347,22 @@ struct hmac_sha1_testvec { { 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d, 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91 } - } + }, + + /* cross page test */ + { + { 'J', 'e', 'f', 'e', 0 }, + + "what do ya want for nothing?", + + { 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74, + 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79 } + + }, + }; +#endif /* CONFIG_CRYPTO_HMAC */ /* * SHA1 test vectors from from FIPS PUB 180-1 |