aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorJames Morris <jmorris@intercode.com.au>2002-11-03 10:13:19 -0800
committerDavid S. Miller <davem@nuts.ninka.net>2002-11-03 10:13:19 -0800
commit464ff46093bd6ed4da11037edda18378b6804c1a (patch)
tree1b3f983799bb2249759c43c4ace3eb4bf6a55d12 /crypto
parent03d4a1cd25137f70857cc524548cb6b34371cce6 (diff)
downloadhistory-464ff46093bd6ed4da11037edda18378b6804c1a.tar.gz
[CRYPTO]: Rework HMAC interface.
Diffstat (limited to 'crypto')
-rw-r--r--crypto/Kconfig14
-rw-r--r--crypto/Makefile3
-rw-r--r--crypto/digest.c62
-rw-r--r--crypto/hmac.c112
-rw-r--r--crypto/tcrypt.c189
-rw-r--r--crypto/tcrypt.h30
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