Skip to contentSkip to conversation

: Add hash type and hmac template

PATCH New Herbert Xu 1 participant 8 messages Aug 21, 2006

Subsystems (6)
lore
Share & tools
lore

Herbert Xu

author maintainer
#0 lore raw

cover : Add hash type and hmac template

Hi:

Dave, these patches are for cryptodev-2.6.

This series of patches adds the new hash crypto type. It completely replaces the existing digest type from the user's side. For now the digest algorithm interface will remain and coexist with the new hash algorithm interface.

The main reasons for the new type are:

1) Be able to return errors from init/update/final/digest.
2) Take a descriptor argument in init/update/final/digest.
3) Use SG on algorithm side for update/digest.
4) Compatibility on the algorithm side.

The first three are needed for async crypto.

For now only the HMAC users have been converted over to the new hash interface. The rest will follow next. I do not currently plan to convert the algorithms to the new interface because there is little benefit. In fact one of the main advantages of the crypto_type setup is the ability to have multiple algorithm types supported by the same user interface.

Apart from that this series is a respin of the HMAC patches which I've posted before. The only difference is that HMAC is now a hash algorithm rather than digest.

Cheers,

Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
author maintainer
#1 lore raw

PATCH 1/7 digest: Added user API for new hash type

[CRYPTO] digest: Added user API for new hash type

The existing digest user interface is inadequate for support asynchronous operations. For one it doesn't return a value to indicate success or failure, nor does it take a per-operation descriptor which is essential for the issuing of requests while other requests are still outstanding.

This patch is the first in a series of steps to remodel the interface for asynchronous operations.

For the ease of transition the new interface will be known as "hash" while the old one will remain as "digest".

This patch also changes sg_next to allow chaining.

---

 crypto/Kconfig          |    4 +
 crypto/Makefile         |    3 
 crypto/digest.c         |  129 ++++++++++++++++++++++++++++--------
 crypto/hash.c           |   61 +++++++++++++++++
 crypto/hmac.c           |   12 +--
 crypto/scatterwalk.h    |    4 -
 include/crypto/algapi.h |    6 +
 include/linux/crypto.h  |  172 ++++++++++++++++++++++++++++++++++++++----------
 8 files changed, 321 insertions(+), 70 deletions(-)
crypto/Kconfig +4 -0
@@ -20,6 +20,10 @@ config CRYPTO_BLKCIPHER
 	tristate
 	select CRYPTO_ALGAPI
 
+config CRYPTO_HASH
+	tristate
+	select CRYPTO_ALGAPI
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
 	select CRYPTO_ALGAPI
crypto/Makefile +3 -0
@@ -10,6 +10,9 @@ obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_al
 
 obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
 
+crypto_hash-objs := hash.o
+obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
+
 obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
 obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
crypto/digest.c +102 -27

187 lines not on this page · raw message

crypto/hash.c new file +61 -0

61 lines not on this page · raw message

crypto/hmac.c +6 -6
@@ -35,9 +35,9 @@ int crypto_alloc_hmac_block(struct crypt
 
 	BUG_ON(!crypto_tfm_alg_blocksize(tfm));
 	
-	tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
-	                                         GFP_KERNEL);
-	if (tfm->crt_digest.dit_hmac_block == NULL)
+	tfm->crt_hash.hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
+					   GFP_KERNEL);
+	if (tfm->crt_hash.hmac_block == NULL)
 		ret = -ENOMEM;
 
 	return ret;
@@ -46,14 +46,14 @@ int crypto_alloc_hmac_block(struct crypt
 
 void crypto_free_hmac_block(struct crypto_tfm *tfm)
 {
-	kfree(tfm->crt_digest.dit_hmac_block);
+	kfree(tfm->crt_hash.hmac_block);
 }
 
 void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
 {
 	unsigned int i;
 	struct scatterlist tmp;
-	char *ipad = tfm->crt_digest.dit_hmac_block;
+	char *ipad = tfm->crt_hash.hmac_block;
 	
 	if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
 		hash_key(tfm, key, *keylen);
@@ -83,7 +83,7 @@ void crypto_hmac_final(struct crypto_tfm
 {
 	unsigned int i;
 	struct scatterlist tmp;
-	char *opad = tfm->crt_digest.dit_hmac_block;
+	char *opad = tfm->crt_hash.hmac_block;
 	
 	if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
 		hash_key(tfm, key, *keylen);
crypto/scatterwalk.h +1 -3
@@ -20,11 +20,9 @@
 
 #include "internal.h"
 
-/* Define sg_next is an inline routine now in case we want to change
-   scatterlist to a linked list later. */
 static inline struct scatterlist *sg_next(struct scatterlist *sg)
 {
-	return sg + 1;
+	return (++sg)->length ? sg : (void *)sg->page;
 }
 
 static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
include/crypto/algapi.h +6 -0
@@ -82,6 +82,7 @@ struct blkcipher_walk {
 };
 
 extern const struct crypto_type crypto_blkcipher_type;
+extern const struct crypto_type crypto_hash_type;
 
 void crypto_mod_put(struct crypto_alg *alg);
 
@@ -136,6 +137,11 @@ static inline struct cipher_alg *crypto_
 	return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher;
 }
 
+static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
+{
+	return crypto_tfm_ctx_aligned(&tfm->base);
+}
+
 static inline void blkcipher_walk_init(struct blkcipher_walk *walk,
 				       struct scatterlist *dst,
 				       struct scatterlist *src,
include/linux/crypto.h +138 -34

253 lines not on this page · raw message

author maintainer
#2 lore raw

PATCH 2/7 hmac: Add crypto template implementation

In reply to Herbert Xu

[CRYPTO] hmac: Add crypto template implementation

This patch rewrites HMAC as a crypto template. This means that HMAC is no longer a hard-coded part of the API. It's now a template that generates standard digest algorithms like any other.

The old HMAC is preserved until all current users are converted.

The same structure can be used by other MACs such as AES-XCBC-MAC.

---

 crypto/Kconfig |    1 
 crypto/hmac.c  |  241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 236 insertions(+), 6 deletions(-)
crypto/Kconfig +1 -0
@@ -34,6 +34,7 @@ config CRYPTO_MANAGER
 
 config CRYPTO_HMAC
 	bool "HMAC support"
+	select CRYPTO_HASH
 	help
 	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
 	  This is required for IPSec.
crypto/hmac.c +235 -6

260 lines not on this page · raw message

author maintainer
#3 lore raw

PATCH 3/7 tcrypt: Use HMAC template and hash interface

In reply to Herbert Xu

[CRYPTO] tcrypt: Use HMAC template and hash interface

This patch converts tcrypt to use the new HMAC template rather than the hard-coded version of HMAC. It also converts all digest users to use the new cipher interface.

---

 crypto/tcrypt.c |  355 ++++++++++++++++++++++++++++++++------------------------
 crypto/tcrypt.h |   23 ---
 2 files changed, 213 insertions(+), 165 deletions(-)
crypto/tcrypt.c +208 -147
@@ -88,9 +88,11 @@ static void test_hash(char *algo, struct
 	unsigned int i, j, k, temp;
 	struct scatterlist sg[8];
 	char result[64];
-	struct crypto_tfm *tfm;
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
 	struct hash_testvec *hash_tv;
 	unsigned int tsize;
+	int ret;
 
 	printk("\ntesting %s\n", algo);
 
@@ -104,27 +106,42 @@ static void test_hash(char *algo, struct
 
 	memcpy(tvmem, template, tsize);
 	hash_tv = (void *)tvmem;
-	tfm = crypto_alloc_tfm(algo, 0);
-	if (tfm == NULL) {
-		printk("failed to load transform for %s\n", algo);
+
+	tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm)) {
+		printk("failed to load transform for %s: %ld\n", algo,
+		       PTR_ERR(tfm));
 		return;
 	}
 
+	desc.tfm = tfm;
+	desc.flags = 0;
+
 	for (i = 0; i < tcount; i++) {
 		printk("test %u:\n", i + 1);
 		memset(result, 0, 64);
 
 		sg_set_buf(&sg[0], hash_tv[i].plaintext, hash_tv[i].psize);
 
-		crypto_digest_init(tfm);
-		crypto_digest_setkey(tfm, hash_tv[i].key, hash_tv[i].ksize);
-		crypto_digest_update(tfm, sg, 1);
-		crypto_digest_final(tfm, result);
+		if (hash_tv[i].ksize) {
+			ret = crypto_hash_setkey(tfm, hash_tv[i].key,
+						 hash_tv[i].ksize);
+			if (ret) {
+				printk("setkey() failed ret=%d\n", ret);
+				goto out;
+			}
+		}
+
+		ret = crypto_hash_digest(&desc, sg, hash_tv[i].psize, result);
+		if (ret) {
+			printk("digest () failed ret=%d\n", ret);
+			goto out;
+		}
 
-		hexdump(result, crypto_tfm_alg_digestsize(tfm));
+		hexdump(result, crypto_hash_digestsize(tfm));
 		printk("%s\n",
 		       memcmp(result, hash_tv[i].digest,
-			      crypto_tfm_alg_digestsize(tfm)) ?
+			      crypto_hash_digestsize(tfm)) ?
 		       "fail" : "pass");
 	}
 
@@ -150,105 +167,35 @@ static void test_hash(char *algo, struct
 					    hash_tv[i].tap[k]);
 			}
 
-			crypto_digest_digest(tfm, sg, hash_tv[i].np, result);
-
-			hexdump(result, crypto_tfm_alg_digestsize(tfm));
-			printk("%s\n",
-			       memcmp(result, hash_tv[i].digest,
-				      crypto_tfm_alg_digestsize(tfm)) ?
-			       "fail" : "pass");
-		}
-	}
-
-	crypto_free_tfm(tfm);
-}
-
-
-#ifdef CONFIG_CRYPTO_HMAC
-
-static void test_hmac(char *algo, struct hmac_testvec *template,
-		      unsigned int tcount)
-{
-	unsigned int i, j, k, temp;
-	struct scatterlist sg[8];
-	char result[64];
-	struct crypto_tfm *tfm;
-	struct hmac_testvec *hmac_tv;
-	unsigned int tsize, klen;
-
-	tfm = crypto_alloc_tfm(algo, 0);
-	if (tfm == NULL) {
-		printk("failed to load transform for %s\n", algo);
-		return;
-	}
-
-	printk("\ntesting hmac_%s\n", algo);
-
-	tsize = sizeof(struct hmac_testvec);
-	tsize *= tcount;
-	if (tsize > TVMEMSIZE) {
-		printk("template (%u) too big for tvmem (%u)\n", tsize,
-		       TVMEMSIZE);
-		goto out;
-	}
-
-	memcpy(tvmem, template, tsize);
-	hmac_tv = (void *)tvmem;
-
-	for (i = 0; i < tcount; i++) {
-		printk("test %u:\n", i + 1);
-		memset(result, 0, sizeof (result));
-
-		klen = hmac_tv[i].ksize;
-		sg_set_buf(&sg[0], hmac_tv[i].plaintext, hmac_tv[i].psize);
+			if (hash_tv[i].ksize) {
+				ret = crypto_hash_setkey(tfm, hash_tv[i].key,
+							 hash_tv[i].ksize);
 
-		crypto_hmac(tfm, hmac_tv[i].key, &klen, sg, 1, result);
-
-		hexdump(result, crypto_tfm_alg_digestsize(tfm));
-		printk("%s\n",
-		       memcmp(result, hmac_tv[i].digest,
-			      crypto_tfm_alg_digestsize(tfm)) ? "fail" :
-		       "pass");
-	}
-
-	printk("\ntesting hmac_%s across pages\n", algo);
-
-	memset(xbuf, 0, XBUFSIZE);
-
-	j = 0;
-	for (i = 0; i < tcount; i++) {
-		if (hmac_tv[i].np) {
-			j++;
-			printk("test %u:\n",j);
-			memset(result, 0, 64);
-
-			temp = 0;
-			klen = hmac_tv[i].ksize;
-			for (k = 0; k < hmac_tv[i].np; k++) {
-				memcpy(&xbuf[IDX[k]],
-				       hmac_tv[i].plaintext + temp,
-				       hmac_tv[i].tap[k]);
-				temp += hmac_tv[i].tap[k];
-				sg_set_buf(&sg[k], &xbuf[IDX[k]],
-					    hmac_tv[i].tap[k]);
+				if (ret) {
+					printk("setkey() failed ret=%d\n", ret);
+					goto out;
+				}
 			}
 
-			crypto_hmac(tfm, hmac_tv[i].key, &klen, sg,
-				    hmac_tv[i].np, result);
-			hexdump(result, crypto_tfm_alg_digestsize(tfm));
+			ret = crypto_hash_digest(&desc, sg, hash_tv[i].psize,
+						 result);
+			if (ret) {
+				printk("digest () failed ret=%d\n", ret);
+				goto out;
+			}
 
+			hexdump(result, crypto_hash_digestsize(tfm));
 			printk("%s\n",
-			       memcmp(result, hmac_tv[i].digest,
-				      crypto_tfm_alg_digestsize(tfm)) ?
+			       memcmp(result, hash_tv[i].digest,
+				      crypto_hash_digestsize(tfm)) ?
 			       "fail" : "pass");
 		}
 	}
+
 out:
-	crypto_free_tfm(tfm);
+	crypto_free_hash(tfm);
 }
 
-#endif	/* CONFIG_CRYPTO_HMAC */
-
 static void test_cipher(char *algo, int enc,
 			struct cipher_testvec *template, unsigned int tcount)
 {
@@ -570,97 +517,202 @@ out:
 	crypto_free_blkcipher(tfm);
 }
 
-static void test_digest_jiffies(struct crypto_tfm *tfm, char *p, int blen,
-				int plen, char *out, int sec)
+static int test_hash_jiffies_digest(struct hash_desc *desc, char *p, int blen,
+				    char *out, int sec)
+{
+	struct scatterlist sg[1];
+	unsigned long start, end;
+	int bcount;
+	int ret;
+
+	for (start = jiffies, end = start + sec * HZ, bcount = 0;
+	     time_before(jiffies, end); bcount++) {
+		sg_set_buf(sg, p, blen);
+		ret = crypto_hash_digest(desc, sg, blen, out);
+		if (ret)
+			return ret;
+	}
+
+	printk("%6u opers/sec, %9lu bytes/sec\n",
+	       bcount / sec, ((long)bcount * blen) / sec);
+
+	return 0;
+}
+
+static int test_hash_jiffies(struct hash_desc *desc, char *p, int blen,
+			     int plen, char *out, int sec)
 {
 	struct scatterlist sg[1];
 	unsigned long start, end;
 	int bcount, pcount;
+	int ret;
+
+	if (plen == blen)
+		return test_hash_jiffies_digest(desc, p, blen, out, sec);
 
 	for (start = jiffies, end = start + sec * HZ, bcount = 0;
 	     time_before(jiffies, end); bcount++) {
-		crypto_digest_init(tfm);
+		ret = crypto_hash_init(desc);
+		if (ret)
+			return ret;
 		for (pcount = 0; pcount < blen; pcount += plen) {
 			sg_set_buf(sg, p + pcount, plen);
-			crypto_digest_update(tfm, sg, 1);
+			ret = crypto_hash_update(desc, sg, plen);
+			if (ret)
+				return ret;
 		}
 		/* we assume there is enough space in 'out' for the result */
-		crypto_digest_final(tfm, out);
+		ret = crypto_hash_final(desc, out);
+		if (ret)
+			return ret;
 	}
 
 	printk("%6u opers/sec, %9lu bytes/sec\n",
 	       bcount / sec, ((long)bcount * blen) / sec);
 
-	return;
+	return 0;
+}
+
+static int test_hash_cycles_digest(struct hash_desc *desc, char *p, int blen,
+				   char *out)
+{
+	struct scatterlist sg[1];
+	unsigned long cycles = 0;
+	int i;
+	int ret;
+
+	local_bh_disable();
+	local_irq_disable();
+
+	/* Warm-up run. */
+	for (i = 0; i < 4; i++) {
+		sg_set_buf(sg, p, blen);
+		ret = crypto_hash_digest(desc, sg, blen, out);
+		if (ret)
+			goto out;
+	}
+
+	/* The real thing. */
+	for (i = 0; i < 8; i++) {
+		cycles_t start, end;
+
+		start = get_cycles();
+
+		sg_set_buf(sg, p, blen);
+		ret = crypto_hash_digest(desc, sg, blen, out);
+		if (ret)
+			goto out;
+
+		end = get_cycles();
+
+		cycles += end - start;
+	}
+
+out:
+	local_irq_enable();
+	local_bh_enable();
+
+	if (ret)
+		return ret;
+
+	printk("%6lu cycles/operation, %4lu cycles/byte\n",
+	       cycles / 8, cycles / (8 * blen));
+
+	return 0;
 }
 
-static void test_digest_cycles(struct crypto_tfm *tfm, char *p, int blen,
-			       int plen, char *out)
+static int test_hash_cycles(struct hash_desc *desc, char *p, int blen,
+			    int plen, char *out)
 {
 	struct scatterlist sg[1];
 	unsigned long cycles = 0;
 	int i, pcount;
+	int ret;
+
+	if (plen == blen)
+		return test_hash_cycles_digest(desc, p, blen, out);
 
 	local_bh_disable();
 	local_irq_disable();
 
 	/* Warm-up run. */
 	for (i = 0; i < 4; i++) {
-		crypto_digest_init(tfm);
+		ret = crypto_hash_init(desc);
+		if (ret)
+			goto out;
 		for (pcount = 0; pcount < blen; pcount += plen) {
 			sg_set_buf(sg, p + pcount, plen);
-			crypto_digest_update(tfm, sg, 1);
+			ret = crypto_hash_update(desc, sg, plen);
+			if (ret)
+				goto out;
 		}
-		crypto_digest_final(tfm, out);
+		crypto_hash_final(desc, out);
+		if (ret)
+			goto out;
 	}
 
 	/* The real thing. */
 	for (i = 0; i < 8; i++) {
 		cycles_t start, end;
 
-		crypto_digest_init(tfm);
-
 		start = get_cycles();
 
+		ret = crypto_hash_init(desc);
+		if (ret)
+			goto out;
 		for (pcount = 0; pcount < blen; pcount += plen) {
 			sg_set_buf(sg, p + pcount, plen);
-			crypto_digest_update(tfm, sg, 1);
+			ret = crypto_hash_update(desc, sg, plen);
+			if (ret)
+				goto out;
 		}
-		crypto_digest_final(tfm, out);
+		ret = crypto_hash_final(desc, out);
+		if (ret)
+			goto out;
 
 		end = get_cycles();
 
 		cycles += end - start;
 	}
 
+out:
 	local_irq_enable();
 	local_bh_enable();
 
+	if (ret)
+		return ret;
+
 	printk("%6lu cycles/operation, %4lu cycles/byte\n",
 	       cycles / 8, cycles / (8 * blen));
 
-	return;
+	return 0;
 }
 
-static void test_digest_speed(char *algo, unsigned int sec,
-			      struct digest_speed *speed)
+static void test_hash_speed(char *algo, unsigned int sec,
+			      struct hash_speed *speed)
 {
-	struct crypto_tfm *tfm;
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
 	char output[1024];
 	int i;
+	int ret;
 
 	printk("\ntesting speed of %s\n", algo);
 
-	tfm = crypto_alloc_tfm(algo, 0);
+	tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
 
-	if (tfm == NULL) {
-		printk("failed to load transform for %s\n", algo);
+	if (IS_ERR(tfm)) {
+		printk("failed to load transform for %s: %ld\n", algo,
+		       PTR_ERR(tfm));
 		return;
 	}
 
-	if (crypto_tfm_alg_digestsize(tfm) > sizeof(output)) {
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	if (crypto_hash_digestsize(tfm) > sizeof(output)) {
 		printk("digestsize(%u) > outputbuffer(%zu)\n",
-		       crypto_tfm_alg_digestsize(tfm), sizeof(output));
+		       crypto_hash_digestsize(tfm), sizeof(output));
 		goto out;
 	}
 
@@ -677,13 +729,20 @@ static void test_digest_speed(char *algo
 		memset(tvmem, 0xff, speed[i].blen);
 
 		if (sec)
-			test_digest_jiffies(tfm, tvmem, speed[i].blen, speed[i].plen, output, sec);
+			ret = test_hash_jiffies(&desc, tvmem, speed[i].blen,
+						speed[i].plen, output, sec);
 		else
-			test_digest_cycles(tfm, tvmem, speed[i].blen, speed[i].plen, output);
+			ret = test_hash_cycles(&desc, tvmem, speed[i].blen,
+					       speed[i].plen, output);
+
+		if (ret) {
+			printk("hashing failed ret=%d\n", ret);
+			break;
+		}
 	}
 
 out:
-	crypto_free_tfm(tfm);
+	crypto_free_hash(tfm);
 }
 
 static void test_deflate(void)
@@ -911,11 +970,12 @@ static void do_test(void)
 		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
 		test_deflate();
 		test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
-#ifdef CONFIG_CRYPTO_HMAC
-		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
-		test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);
-		test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS);
-#endif
+		test_hash("hmac(md5)", hmac_md5_tv_template,
+			  HMAC_MD5_TEST_VECTORS);
+		test_hash("hmac(sha1)", hmac_sha1_tv_template,
+			  HMAC_SHA1_TEST_VECTORS);
+		test_hash("hmac(sha256)", hmac_sha256_tv_template,
+			  HMAC_SHA256_TEST_VECTORS);
 
 		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
 		break;
@@ -1106,20 +1166,21 @@ static void do_test(void)
 			    XETA_DEC_TEST_VECTORS);
 		break;
 
-#ifdef CONFIG_CRYPTO_HMAC
 	case 100:
-		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
+		test_hash("hmac(md5)", hmac_md5_tv_template,
+			  HMAC_MD5_TEST_VECTORS);
 		break;
 
 	case 101:
-		test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);
+		test_hash("hmac(sha1)", hmac_sha1_tv_template,
+			  HMAC_SHA1_TEST_VECTORS);
 		break;
 
 	case 102:
-		test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS);
+		test_hash("hmac(sha256)", hmac_sha256_tv_template,
+			  HMAC_SHA256_TEST_VECTORS);
 		break;
 
-#endif
 
 	case 200:
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
@@ -1188,51 +1249,51 @@ static void do_test(void)
 		/* fall through */
 
 	case 301:
-		test_digest_speed("md4", sec, generic_digest_speed_template);
+		test_hash_speed("md4", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 302:
-		test_digest_speed("md5", sec, generic_digest_speed_template);
+		test_hash_speed("md5", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 303:
-		test_digest_speed("sha1", sec, generic_digest_speed_template);
+		test_hash_speed("sha1", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 304:
-		test_digest_speed("sha256", sec, generic_digest_speed_template);
+		test_hash_speed("sha256", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 305:
-		test_digest_speed("sha384", sec, generic_digest_speed_template);
+		test_hash_speed("sha384", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 306:
-		test_digest_speed("sha512", sec, generic_digest_speed_template);
+		test_hash_speed("sha512", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 307:
-		test_digest_speed("wp256", sec, generic_digest_speed_template);
+		test_hash_speed("wp256", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 308:
-		test_digest_speed("wp384", sec, generic_digest_speed_template);
+		test_hash_speed("wp384", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 309:
-		test_digest_speed("wp512", sec, generic_digest_speed_template);
+		test_hash_speed("wp512", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 310:
-		test_digest_speed("tgr128", sec, generic_digest_speed_template);
+		test_hash_speed("tgr128", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 311:
-		test_digest_speed("tgr160", sec, generic_digest_speed_template);
+		test_hash_speed("tgr160", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 312:
-		test_digest_speed("tgr192", sec, generic_digest_speed_template);
+		test_hash_speed("tgr192", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 
 	case 399:
crypto/tcrypt.h +5 -18
@@ -36,16 +36,6 @@ struct hash_testvec {
 	unsigned char ksize;
 };
 
-struct hmac_testvec {
-	char key[128];
-	char plaintext[128];
-	char digest[MAX_DIGEST_SIZE];
-	unsigned char tap[MAX_TAP];
-	unsigned char ksize;
-	unsigned char psize;
-	unsigned char np;
-};
-
 struct cipher_testvec {
 	char key[MAX_KEYLEN] __attribute__ ((__aligned__(4)));
 	char iv[MAX_IVLEN];
@@ -65,7 +55,7 @@ struct cipher_speed {
 	unsigned int blen;
 };
 
-struct digest_speed {
+struct hash_speed {
 	unsigned int blen;	/* buffer length */
 	unsigned int plen;	/* per-update length */
 };
@@ -697,14 +687,13 @@ static struct hash_testvec tgr128_tv_tem
 	},
 };
 
-#ifdef CONFIG_CRYPTO_HMAC
 /*
  * HMAC-MD5 test vectors from RFC2202
  * (These need to be fixed to not use strlen).
  */
 #define HMAC_MD5_TEST_VECTORS	7
 
-static struct hmac_testvec hmac_md5_tv_template[] =
+static struct hash_testvec hmac_md5_tv_template[] =
 {
 	{
 		.key	= { [0 ... 15] =  0x0b },
@@ -768,7 +757,7 @@ static struct hmac_testvec hmac_md5_tv_t
  */
 #define HMAC_SHA1_TEST_VECTORS	7
 
-static struct hmac_testvec hmac_sha1_tv_template[] = {
+static struct hash_testvec hmac_sha1_tv_template[] = {
 	{
 		.key	= { [0 ... 19] = 0x0b },
 		.ksize	= 20,
@@ -833,7 +822,7 @@ static struct hmac_testvec hmac_sha1_tv_
  */
 #define HMAC_SHA256_TEST_VECTORS	10
 
-static struct hmac_testvec hmac_sha256_tv_template[] = {
+static struct hash_testvec hmac_sha256_tv_template[] = {
 	{
 		.key	= { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
 			    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
@@ -944,8 +933,6 @@ static struct hmac_testvec hmac_sha256_t
 	},
 };
 
-#endif	/* CONFIG_CRYPTO_HMAC */
-
 /*
  * DES test vectors.
  */
@@ -3160,7 +3147,7 @@ static struct cipher_speed des_speed_tem
 /*
  * Digest speed tests
  */
-static struct digest_speed generic_digest_speed_template[] = {
+static struct hash_speed generic_hash_speed_template[] = {
 	{ .blen = 16, 	.plen = 16, },
 	{ .blen = 64,	.plen = 16, },
 	{ .blen = 64,	.plen = 64, },
author maintainer
#4 lore raw

PATCH 4/7 : Use HMAC template and hash interface

In reply to Herbert Xu

[IPSEC]: Use HMAC template and hash interface

This patch converts IPsec to use the new HMAC template. The names of existing simple digest algorithms may still be used to refer to their HMAC composites.

The same structure can be used by other MACs such as AES-XCBC-MAC.

This patch also switches from the digest interface to hash.

---

 include/net/ah.h     |   29 ++++++++++++++++++-----------
 include/net/esp.h    |   26 +++++++++++++++-----------
 include/net/xfrm.h   |    9 +++++----
 net/ipv4/ah4.c       |   36 ++++++++++++++++++++++++------------
 net/ipv4/esp4.c      |   36 +++++++++++++++++++++---------------
 net/ipv6/ah6.c       |   35 +++++++++++++++++++++++------------
 net/ipv6/esp6.c      |   42 ++++++++++++++++++++++++------------------
 net/xfrm/xfrm_algo.c |   40 +++++++++++++++++++++++++++-------------
 8 files changed, 157 insertions(+), 96 deletions(-)
include/net/ah.h +18 -11
@@ -15,22 +15,29 @@ struct ah_data
 	int			icv_full_len;
 	int			icv_trunc_len;
 
-	void			(*icv)(struct ah_data*,
-	                               struct sk_buff *skb, u8 *icv);
-
-	struct crypto_tfm	*tfm;
+	struct crypto_hash	*tfm;
 };
 
-static inline void
-ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data)
+static inline int ah_mac_digest(struct ah_data *ahp, struct sk_buff *skb,
+				u8 *auth_data)
 {
-	struct crypto_tfm *tfm = ahp->tfm;
+	struct hash_desc desc;
+	int err;
+
+	desc.tfm = ahp->tfm;
+	desc.flags = 0;
 
 	memset(auth_data, 0, ahp->icv_trunc_len);
-	crypto_hmac_init(tfm, ahp->key, &ahp->key_len);
-	skb_icv_walk(skb, tfm, 0, skb->len, crypto_hmac_update);
-	crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_icv);
-	memcpy(auth_data, ahp->work_icv, ahp->icv_trunc_len);
+	err = crypto_hash_init(&desc);
+	if (unlikely(err))
+		goto out;
+	err = skb_icv_walk(skb, &desc, 0, skb->len, crypto_hash_update);
+	if (unlikely(err))
+		goto out;
+	err = crypto_hash_final(&desc, ahp->work_icv);
+
+out:
+	return err;
 }
 
 #endif
include/net/esp.h +15 -11
@@ -35,7 +35,7 @@ struct esp_data
 		void			(*icv)(struct esp_data*,
 		                               struct sk_buff *skb,
 		                               int offset, int len, u8 *icv);
-		struct crypto_tfm	*tfm;
+		struct crypto_hash	*tfm;
 	} auth;
 };
 
@@ -43,18 +43,22 @@ extern int skb_to_sgvec(struct sk_buff *
 extern int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
 extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len);
 
-static inline void
-esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset,
-                int len, u8 *auth_data)
+static inline int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb,
+				 int offset, int len)
 {
-	struct crypto_tfm *tfm = esp->auth.tfm;
-	char *icv = esp->auth.work_icv;
+	struct hash_desc desc;
+	int err;
 
-	memset(auth_data, 0, esp->auth.icv_trunc_len);
-	crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len);
-	skb_icv_walk(skb, tfm, offset, len, crypto_hmac_update);
-	crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, icv);
-	memcpy(auth_data, icv, esp->auth.icv_trunc_len);
+	desc.tfm = esp->auth.tfm;
+	desc.flags = 0;
+
+	err = crypto_hash_init(&desc);
+	if (unlikely(err))
+		return err;
+	err = skb_icv_walk(skb, &desc, offset, len, crypto_hash_update);
+	if (unlikely(err))
+		return err;
+	return crypto_hash_final(&desc, esp->auth.work_icv);
 }
 
 #endif
include/net/xfrm.h +5 -4
@@ -984,12 +984,13 @@ extern struct xfrm_algo_desc *xfrm_aalg_
 extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
 extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
 
-struct crypto_tfm;
+struct hash_desc;
 struct scatterlist;
-typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, unsigned int);
+typedef int (icv_update_fn_t)(struct hash_desc *, struct scatterlist *,
+			      unsigned int);
 
-extern void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
-			 int offset, int len, icv_update_fn_t icv_update);
+extern int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *tfm,
+			int offset, int len, icv_update_fn_t icv_update);
 
 static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b,
 				int family)
net/ipv4/ah4.c +24 -12
@@ -1,3 +1,4 @@
+#include <linux/err.h>
 #include <linux/module.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
@@ -97,7 +98,10 @@ static int ah_output(struct xfrm_state *
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
 	xfrm_aevent_doreplay(x);
-	ahp->icv(ahp, skb, ah->auth_data);
+	err = ah_mac_digest(ahp, skb, ah->auth_data);
+	if (err)
+		goto error;
+	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
 
 	top_iph->tos = iph->tos;
 	top_iph->ttl = iph->ttl;
@@ -119,6 +123,7 @@ static int ah_input(struct xfrm_state *x
 {
 	int ah_hlen;
 	int ihl;
+	int err = -EINVAL;
 	struct iphdr *iph;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
@@ -166,8 +171,11 @@ static int ah_input(struct xfrm_state *x
 		
 		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
 		skb_push(skb, ihl);
-		ahp->icv(ahp, skb, ah->auth_data);
-		if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
+		err = ah_mac_digest(ahp, skb, ah->auth_data);
+		if (err)
+			goto out;
+		err = -EINVAL;
+		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
 			x->stats.integrity_failed++;
 			goto out;
 		}
@@ -179,7 +187,7 @@ static int ah_input(struct xfrm_state *x
 	return 0;
 
 out:
-	return -EINVAL;
+	return err;
 }
 
 static void ah4_err(struct sk_buff *skb, u32 info)
@@ -204,6 +212,7 @@ static int ah_init_state(struct xfrm_sta
 {
 	struct ah_data *ahp = NULL;
 	struct xfrm_algo_desc *aalg_desc;
+	struct crypto_hash *tfm;
 
 	if (!x->aalg)
 		goto error;
@@ -223,24 +232,27 @@ static int ah_init_state(struct xfrm_sta
 
 	ahp->key = x->aalg->alg_key;
 	ahp->key_len = (x->aalg->alg_key_len+7)/8;
-	ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
-	if (!ahp->tfm)
+	tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
+		goto error;
+
+	ahp->tfm = tfm;
+	if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))
 		goto error;
-	ahp->icv = ah_hmac_digest;
 	
 	/*
 	 * Lookup the algorithm description maintained by xfrm_algo,
 	 * verify crypto transform properties, and store information
 	 * we need for AH processing.  This lookup cannot fail here
-	 * after a successful crypto_alloc_tfm().
+	 * after a successful crypto_alloc_hash().
 	 */
 	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
 	BUG_ON(!aalg_desc);
 
 	if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-	    crypto_tfm_alg_digestsize(ahp->tfm)) {
+	    crypto_hash_digestsize(tfm)) {
 		printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
-		       x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm),
+		       x->aalg->alg_name, crypto_hash_digestsize(tfm),
 		       aalg_desc->uinfo.auth.icv_fullbits/8);
 		goto error;
 	}
@@ -264,7 +276,7 @@ static int ah_init_state(struct xfrm_sta
 error:
 	if (ahp) {
 		kfree(ahp->work_icv);
-		crypto_free_tfm(ahp->tfm);
+		crypto_free_hash(ahp->tfm);
 		kfree(ahp);
 	}
 	return -EINVAL;
@@ -279,7 +291,7 @@ static void ah_destroy(struct xfrm_state
 
 	kfree(ahp->work_icv);
 	ahp->work_icv = NULL;
-	crypto_free_tfm(ahp->tfm);
+	crypto_free_hash(ahp->tfm);
 	ahp->tfm = NULL;
 	kfree(ahp);
 }
net/ipv4/esp4.c +21 -15
@@ -121,9 +121,9 @@ static int esp_output(struct xfrm_state 
 	}
 
 	if (esp->auth.icv_full_len) {
-		esp->auth.icv(esp, skb, (u8*)esph-skb->data,
-		              sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail);
-		pskb_put(skb, trailer, alen);
+		err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
+				     sizeof(*esph) + esp->conf.ivlen + clen);
+		memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
 	}
 
 	ip_send_check(top_iph);
@@ -163,15 +163,16 @@ static int esp_input(struct xfrm_state *
 
 	/* If integrity check is required, do this. */
 	if (esp->auth.icv_full_len) {
-		u8 sum[esp->auth.icv_full_len];
-		u8 sum1[alen];
-		
-		esp->auth.icv(esp, skb, 0, skb->len-alen, sum);
+		u8 sum[alen];
 
-		if (skb_copy_bits(skb, skb->len-alen, sum1, alen))
+		err = esp_mac_digest(esp, skb, 0, skb->len - alen);
+		if (err)
+			goto out;
+
+		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
 			BUG();
 
-		if (unlikely(memcmp(sum, sum1, alen))) {
+		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
 			x->stats.integrity_failed++;
 			goto out;
 		}
@@ -307,7 +308,7 @@ static void esp_destroy(struct xfrm_stat
 	esp->conf.tfm = NULL;
 	kfree(esp->conf.ivec);
 	esp->conf.ivec = NULL;
-	crypto_free_tfm(esp->auth.tfm);
+	crypto_free_hash(esp->auth.tfm);
 	esp->auth.tfm = NULL;
 	kfree(esp->auth.work_icv);
 	esp->auth.work_icv = NULL;
@@ -335,22 +336,27 @@ static int esp_init_state(struct xfrm_st
 
 	if (x->aalg) {
 		struct xfrm_algo_desc *aalg_desc;
+		struct crypto_hash *hash;
 
 		esp->auth.key = x->aalg->alg_key;
 		esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
-		esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
-		if (esp->auth.tfm == NULL)
+		hash = crypto_alloc_hash(x->aalg->alg_name, 0,
+					 CRYPTO_ALG_ASYNC);
+		if (IS_ERR(hash))
+			goto error;
+
+		esp->auth.tfm = hash;
+		if (crypto_hash_setkey(hash, esp->auth.key, esp->auth.key_len))
 			goto error;
-		esp->auth.icv = esp_hmac_digest;
 
 		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
 		BUG_ON(!aalg_desc);
 
 		if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-		    crypto_tfm_alg_digestsize(esp->auth.tfm)) {
+		    crypto_hash_digestsize(hash)) {
 			NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
 				 x->aalg->alg_name,
-				 crypto_tfm_alg_digestsize(esp->auth.tfm),
+				 crypto_hash_digestsize(hash),
 				 aalg_desc->uinfo.auth.icv_fullbits/8);
 			goto error;
 		}
net/ipv6/ah6.c +23 -12
@@ -213,7 +213,10 @@ static int ah6_output(struct xfrm_state 
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
 	xfrm_aevent_doreplay(x);
-	ahp->icv(ahp, skb, ah->auth_data);
+	err = ah_mac_digest(ahp, skb, ah->auth_data);
+	if (err)
+		goto error_free_iph;
+	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
 
 	err = 0;
 
@@ -251,6 +254,7 @@ static int ah6_input(struct xfrm_state *
 	u16 hdr_len;
 	u16 ah_hlen;
 	int nexthdr;
+	int err = -EINVAL;
 
 	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
 		goto out;
@@ -292,8 +296,11 @@ static int ah6_input(struct xfrm_state *
 		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
 		memset(ah->auth_data, 0, ahp->icv_trunc_len);
 		skb_push(skb, hdr_len);
-		ahp->icv(ahp, skb, ah->auth_data);
-		if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
+		err = ah_mac_digest(ahp, skb, ah->auth_data);
+		if (err)
+			goto free_out;
+		err = -EINVAL;
+		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
 			LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
 			x->stats.integrity_failed++;
 			goto free_out;
@@ -310,7 +317,7 @@ static int ah6_input(struct xfrm_state *
 free_out:
 	kfree(tmp_hdr);
 out:
-	return -EINVAL;
+	return err;
 }
 
 static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 
@@ -338,6 +345,7 @@ static int ah6_init_state(struct xfrm_st
 {
 	struct ah_data *ahp = NULL;
 	struct xfrm_algo_desc *aalg_desc;
+	struct crypto_hash *tfm;
 
 	if (!x->aalg)
 		goto error;
@@ -355,24 +363,27 @@ static int ah6_init_state(struct xfrm_st
 
 	ahp->key = x->aalg->alg_key;
 	ahp->key_len = (x->aalg->alg_key_len+7)/8;
-	ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
-	if (!ahp->tfm)
+	tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
+		goto error;
+
+	ahp->tfm = tfm;
+	if (crypto_hash_setkey(tfm, ahp->key, ahp->key_len))
 		goto error;
-	ahp->icv = ah_hmac_digest;
 	
 	/*
 	 * Lookup the algorithm description maintained by xfrm_algo,
 	 * verify crypto transform properties, and store information
 	 * we need for AH processing.  This lookup cannot fail here
-	 * after a successful crypto_alloc_tfm().
+	 * after a successful crypto_alloc_hash().
 	 */
 	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
 	BUG_ON(!aalg_desc);
 
 	if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-	    crypto_tfm_alg_digestsize(ahp->tfm)) {
+	    crypto_hash_digestsize(tfm)) {
 		printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
-		       x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm),
+		       x->aalg->alg_name, crypto_hash_digestsize(tfm),
 		       aalg_desc->uinfo.auth.icv_fullbits/8);
 		goto error;
 	}
@@ -396,7 +407,7 @@ static int ah6_init_state(struct xfrm_st
 error:
 	if (ahp) {
 		kfree(ahp->work_icv);
-		crypto_free_tfm(ahp->tfm);
+		crypto_free_hash(ahp->tfm);
 		kfree(ahp);
 	}
 	return -EINVAL;
@@ -411,7 +422,7 @@ static void ah6_destroy(struct xfrm_stat
 
 	kfree(ahp->work_icv);
 	ahp->work_icv = NULL;
-	crypto_free_tfm(ahp->tfm);
+	crypto_free_hash(ahp->tfm);
 	ahp->tfm = NULL;
 	kfree(ahp);
 }
net/ipv6/esp6.c +24 -18

79 lines not on this page · raw message

net/xfrm/xfrm_algo.c +27 -13
@@ -30,7 +30,8 @@
  */
 static struct xfrm_algo_desc aalg_list[] = {
 {
-	.name = "digest_null",
+	.name = "hmac(digest_null)",
+	.compat = "digest_null",
 	
 	.uinfo = {
 		.auth = {
@@ -47,7 +48,8 @@ static struct xfrm_algo_desc aalg_list[]
 	}
 },
 {
-	.name = "md5",
+	.name = "hmac(md5)",
+	.compat = "md5",
 
 	.uinfo = {
 		.auth = {
@@ -64,7 +66,8 @@ static struct xfrm_algo_desc aalg_list[]
 	}
 },
 {
-	.name = "sha1",
+	.name = "hmac(sha1)",
+	.compat = "sha1",
 
 	.uinfo = {
 		.auth = {
@@ -81,7 +84,8 @@ static struct xfrm_algo_desc aalg_list[]
 	}
 },
 {
-	.name = "sha256",
+	.name = "hmac(sha256)",
+	.compat = "sha256",
 
 	.uinfo = {
 		.auth = {
@@ -98,7 +102,8 @@ static struct xfrm_algo_desc aalg_list[]
 	}
 },
 {
-	.name = "ripemd160",
+	.name = "hmac(ripemd160)",
+	.compat = "ripemd160",
 
 	.uinfo = {
 		.auth = {
@@ -480,11 +485,12 @@ EXPORT_SYMBOL_GPL(xfrm_count_enc_support
 
 /* Move to common area: it is shared with AH. */
 
-void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
-		  int offset, int len, icv_update_fn_t icv_update)
+int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
+		 int offset, int len, icv_update_fn_t icv_update)
 {
 	int start = skb_headlen(skb);
 	int i, copy = start - offset;
+	int err;
 	struct scatterlist sg;
 
 	/* Checksum header. */
@@ -496,10 +502,12 @@ void skb_icv_walk(const struct sk_buff *
 		sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
 		sg.length = copy;
 		
-		icv_update(tfm, &sg, 1);
+		err = icv_update(desc, &sg, copy);
+		if (unlikely(err))
+			return err;
 		
 		if ((len -= copy) == 0)
-			return;
+			return 0;
 		offset += copy;
 	}
 
@@ -519,10 +527,12 @@ void skb_icv_walk(const struct sk_buff *
 			sg.offset = frag->page_offset + offset-start;
 			sg.length = copy;
 			
-			icv_update(tfm, &sg, 1);
+			err = icv_update(desc, &sg, copy);
+			if (unlikely(err))
+				return err;
 
 			if (!(len -= copy))
-				return;
+				return 0;
 			offset += copy;
 		}
 		start = end;
@@ -540,15 +550,19 @@ void skb_icv_walk(const struct sk_buff *
 			if ((copy = end - offset) > 0) {
 				if (copy > len)
 					copy = len;
-				skb_icv_walk(list, tfm, offset-start, copy, icv_update);
+				err = skb_icv_walk(list, desc, offset-start,
+						   copy, icv_update);
+				if (unlikely(err))
+					return err;
 				if ((len -= copy) == 0)
-					return;
+					return 0;
 				offset += copy;
 			}
 			start = end;
 		}
 	}
 	BUG_ON(len);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(skb_icv_walk);
 
author maintainer
#5 lore raw

PATCH 5/7 : Use HMAC template and hash interface

In reply to Herbert Xu

[SCTP]: Use HMAC template and hash interface

This patch converts SCTP to use the new HMAC template and hash interface.

---

 include/net/sctp/constants.h |    4 ++--
 include/net/sctp/sctp.h      |   11 -----------
 include/net/sctp/structs.h   |    3 ++-
 net/sctp/endpointola.c       |    2 +-
 net/sctp/sm_make_chunk.c     |   37 +++++++++++++++++++++++++++----------
 net/sctp/socket.c            |    6 +++---
 6 files changed, 35 insertions(+), 28 deletions(-)
include/net/sctp/constants.h +2 -2
@@ -312,9 +312,9 @@ enum { SCTP_MAX_GABS = 16 };
 				 */
 
 #if defined (CONFIG_SCTP_HMAC_MD5)
-#define SCTP_COOKIE_HMAC_ALG "md5"
+#define SCTP_COOKIE_HMAC_ALG "hmac(md5)"
 #elif defined (CONFIG_SCTP_HMAC_SHA1)
-#define SCTP_COOKIE_HMAC_ALG "sha1"
+#define SCTP_COOKIE_HMAC_ALG "hmac(sha1)"
 #else
 #define SCTP_COOKIE_HMAC_ALG NULL
 #endif
include/net/sctp/sctp.h +0 -11
@@ -330,17 +330,6 @@ static inline void sctp_v6_exit(void) { 
 
 #endif /* #if defined(CONFIG_IPV6) */
 
-/* Some wrappers, in case crypto not available. */
-#if defined (CONFIG_CRYPTO_HMAC)
-#define sctp_crypto_alloc_tfm crypto_alloc_tfm
-#define sctp_crypto_free_tfm crypto_free_tfm
-#define sctp_crypto_hmac crypto_hmac
-#else
-#define sctp_crypto_alloc_tfm(x...) NULL
-#define sctp_crypto_free_tfm(x...)
-#define sctp_crypto_hmac(x...)
-#endif
-
 
 /* Map an association to an assoc_id. */
 static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
include/net/sctp/structs.h +2 -1
@@ -87,6 +87,7 @@ struct sctp_bind_addr;
 struct sctp_ulpq;
 struct sctp_ep_common;
 struct sctp_ssnmap;
+struct crypto_hash;
 
 
 #include <net/sctp/tsnmap.h>
@@ -264,7 +265,7 @@ struct sctp_sock {
 	struct sctp_pf *pf;
 
 	/* Access to HMAC transform. */
-	struct crypto_tfm *hmac;
+	struct crypto_hash *hmac;
 
 	/* What is our base endpointer? */
 	struct sctp_endpoint *ep;
net/sctp/endpointola.c +1 -1
@@ -172,7 +172,7 @@ static void sctp_endpoint_destroy(struct
 	sctp_unhash_endpoint(ep);
 
 	/* Free up the HMAC transform. */
-	sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
+	crypto_free_hash(sctp_sk(ep->base.sk)->hmac);
 
 	/* Cleanup. */
 	sctp_inq_free(&ep->base.inqueue);
net/sctp/sm_make_chunk.c +27 -10
@@ -1294,10 +1294,8 @@ static sctp_cookie_param_t *sctp_pack_co
 
 	retval = kmalloc(*cookie_len, GFP_ATOMIC);
 
-	if (!retval) {
-		*cookie_len = 0;
+	if (!retval)
 		goto nodata;
-	}
 
 	/* Clear this memory since we are sending this data structure
 	 * out on the network.
@@ -1333,19 +1331,29 @@ static sctp_cookie_param_t *sctp_pack_co
 	       ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
 
   	if (sctp_sk(ep->base.sk)->hmac) {
+		struct hash_desc desc;
+
 		/* Sign the message.  */
 		sg.page = virt_to_page(&cookie->c);
 		sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE;
 		sg.length = bodysize;
 		keylen = SCTP_SECRET_SIZE;
 		key = (char *)ep->secret_key[ep->current_key];
+  		desc.tfm = sctp_sk(ep->base.sk)->hmac;
+  		desc.flags = 0;
 
-		sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
-				 &sg, 1, cookie->signature);
+		if (crypto_hash_setkey(desc.tfm, key, keylen) ||
+		    crypto_hash_digest(&desc, &sg, bodysize, cookie->signature))
+			goto free_cookie;
 	}
 
-nodata:
 	return retval;
+
+free_cookie:
+	kfree(retval);
+nodata:
+	*cookie_len = 0;
+	return NULL;
 }
 
 /* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */
@@ -1366,6 +1374,7 @@ struct sctp_association *sctp_unpack_coo
 	sctp_scope_t scope;
 	struct sk_buff *skb = chunk->skb;
 	struct timeval tv;
+	struct hash_desc desc;
 
 	/* Header size is static data prior to the actual cookie, including
 	 * any padding.
@@ -1401,17 +1410,25 @@ struct sctp_association *sctp_unpack_coo
 	sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE;
 	sg.length = bodysize;
 	key = (char *)ep->secret_key[ep->current_key];
+	desc.tfm = sctp_sk(ep->base.sk)->hmac;
+	desc.flags = 0;
 
 	memset(digest, 0x00, SCTP_SIGNATURE_SIZE);
-	sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg,
-			 1, digest);
+	if (crypto_hash_setkey(desc.tfm, key, keylen) ||
+	    crypto_hash_digest(&desc, &sg, bodysize, digest)) {
+		*error = -SCTP_IERROR_NOMEM;
+		goto fail;
+	}
 
 	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
 		/* Try the previous key. */
 		key = (char *)ep->secret_key[ep->last_key];
 		memset(digest, 0x00, SCTP_SIGNATURE_SIZE);
-		sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
-				 &sg, 1, digest);
+		if (crypto_hash_setkey(desc.tfm, key, keylen) ||
+		    crypto_hash_digest(&desc, &sg, bodysize, digest)) {
+			*error = -SCTP_IERROR_NOMEM;
+			goto fail;
+		}
 
 		if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
 			/* Yikes!  Still bad signature! */
net/sctp/socket.c +3 -3
@@ -4842,7 +4842,7 @@ SCTP_STATIC int sctp_stream_listen(struc
 int sctp_inet_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
-	struct crypto_tfm *tfm=NULL;
+	struct crypto_hash *tfm = NULL;
 	int err = -EINVAL;
 
 	if (unlikely(backlog < 0))
@@ -4855,7 +4855,7 @@ int sctp_inet_listen(struct socket *sock
 
 	/* Allocate HMAC for generating cookie. */
 	if (sctp_hmac_alg) {
-		tfm = sctp_crypto_alloc_tfm(sctp_hmac_alg, 0);
+		tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
 		if (!tfm) {
 			err = -ENOSYS;
 			goto out;
@@ -4881,7 +4881,7 @@ out:
 	sctp_release_sock(sk);
 	return err;
 cleanup:
-	sctp_crypto_free_tfm(tfm);
+	crypto_free_hash(tfm);
 	goto out;
 }
 
author maintainer
#6 lore raw

PATCH 6/7 doc: Update documentation for hash and me

In reply to Herbert Xu

[CRYPTO] doc: Update documentation for hash and me

This patch updates the documentation to reflect the switch from digest to hash. It also replaces notes about emailing James Morris to refer to me instead.

---

 Documentation/crypto/api-intro.txt |   36 ++++++++++++++++++++++--------------
 1 files changed, 22 insertions(+), 14 deletions(-)
Documentation/crypto/api-intro.txt +22 -14
@@ -19,15 +19,14 @@ At the lowest level are algorithms, whic
 API.
 
 'Transforms' are user-instantiated objects, which maintain state, handle all
-of the implementation logic (e.g. manipulating page vectors), provide an 
-abstraction to the underlying algorithms, and handle common logical 
-operations (e.g. cipher modes, HMAC for digests).  However, at the user 
+of the implementation logic (e.g. manipulating page vectors) and provide an 
+abstraction to the underlying algorithms.  However, at the user 
 level they are very simple.
 
 Conceptually, the API layering looks like this:
 
   [transform api]  (user interface)
-  [transform ops]  (per-type logic glue e.g. cipher.c, digest.c)
+  [transform ops]  (per-type logic glue e.g. cipher.c, compress.c)
   [algorithm api]  (for registering algorithms)
   
 The idea is to make the user interface and algorithm registration API
@@ -44,22 +43,27 @@ under development.
 Here's an example of how to use the API:
 
 	#include <linux/crypto.h>
+	#include <linux/err.h>
+	#include <linux/scatterlist.h>
 	
 	struct scatterlist sg[2];
 	char result[128];
-	struct crypto_tfm *tfm;
+	struct crypto_hash *tfm;
+	struct hash_desc desc;
 	
-	tfm = crypto_alloc_tfm("md5", 0);
-	if (tfm == NULL)
+	tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
 		fail();
 		
 	/* ... set up the scatterlists ... */
+
+	desc.tfm = tfm;
+	desc.flags = 0;
 	
-	crypto_digest_init(tfm);
-	crypto_digest_update(tfm, &sg, 2);
-	crypto_digest_final(tfm, result);
+	if (crypto_hash_digest(&desc, &sg, 2, result))
+		fail();
 	
-	crypto_free_tfm(tfm);
+	crypto_free_hash(tfm);
 
     
 Many real examples are available in the regression test module (tcrypt.c).
@@ -126,7 +130,7 @@ might already be working on.
 BUGS
 
 Send bug reports to:
-James Morris <[email protected]>
+Herbert Xu <[email protected]>
 Cc: David S. Miller <[email protected]>
 
 
@@ -134,13 +138,14 @@ FURTHER INFORMATION
 
 For further patches and various updates, including the current TODO
 list, see:
-http://samba.org/~jamesm/crypto/
+http://gondor.apana.org.au/~herbert/crypto/
 
 
 AUTHORS
 
 James Morris
 David S. Miller
+Herbert Xu
 
 
 CREDITS
@@ -238,8 +243,11 @@ Anubis algorithm contributors:
 Tiger algorithm contributors:
   Aaron Grothe
 
+VIA PadLock contributors:
+  Michal Ludvig
+
 Generic scatterwalk code by Adam J. Richter <[email protected]>
 
 Please send any credits updates or corrections to:
-James Morris <[email protected]>
+Herbert Xu <[email protected]>
 
author maintainer
#7 lore raw

PATCH 7/7 digest: Remove old HMAC implementation

In reply to Herbert Xu

[CRYPTO] digest: Remove old HMAC implementation

This patch removes the old HMAC implementation now that nobody uses it anymore.

---

 crypto/Kconfig         |    2 
 crypto/digest.c        |    3 -
 crypto/hmac.c          |  101 -------------------------------------------------
 crypto/internal.h      |   13 ------
 include/linux/crypto.h |   16 -------
 5 files changed, 2 insertions(+), 133 deletions(-)
crypto/Kconfig +1 -1
@@ -33,7 +33,7 @@ config CRYPTO_MANAGER
 	  cbc(aes).
 
 config CRYPTO_HMAC
-	bool "HMAC support"
+	tristate "HMAC support"
 	select CRYPTO_HASH
 	help
 	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
crypto/digest.c +1 -2
@@ -191,10 +191,9 @@ int crypto_init_digest_ops(struct crypto
 	ops->setkey	= dalg->dia_setkey ? setkey : nosetkey;
 	ops->digestsize	= dalg->dia_digestsize;
 	
-	return crypto_alloc_hmac_block(tfm);
+	return 0;
 }
 
 void crypto_exit_digest_ops(struct crypto_tfm *tfm)
 {
-	crypto_free_hmac_block(tfm);
 }
crypto/hmac.c +0 -101

107 lines not on this page · raw message

crypto/internal.h +0 -13
@@ -73,19 +73,6 @@ static inline void crypto_yield(u32 flag
 		cond_resched();
 }
 
-#ifdef CONFIG_CRYPTO_HMAC
-int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
-void crypto_free_hmac_block(struct crypto_tfm *tfm);
-#else
-static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
-{
-	return 0;
-}
-
-static inline void crypto_free_hmac_block(struct crypto_tfm *tfm)
-{ }
-#endif
-
 #ifdef CONFIG_PROC_FS
 void __init crypto_init_proc(void);
 void __exit crypto_exit_proc(void);
include/linux/crypto.h +0 -16
@@ -295,9 +295,6 @@ struct hash_tfm {
 		      unsigned int nsg, u8 *out);
 	int (*setkey)(struct crypto_hash *tfm, const u8 *key,
 		      unsigned int keylen);
-#ifdef CONFIG_CRYPTO_HMAC
-	void *hmac_block;
-#endif
 	unsigned int digestsize;
 };
 
@@ -872,18 +869,5 @@ static inline int crypto_comp_decompress
 	return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen);
 }
 
-/*
- * HMAC support.
- */
-#ifdef CONFIG_CRYPTO_HMAC
-void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen);
-void crypto_hmac_update(struct crypto_tfm *tfm,
-                        struct scatterlist *sg, unsigned int nsg);
-void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
-                       unsigned int *keylen, u8 *out);
-void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
-                 struct scatterlist *sg, unsigned int nsg, u8 *out);
-#endif	/* CONFIG_CRYPTO_HMAC */
-
 #endif	/* _LINUX_CRYPTO_H */