Sfoglia il codice sorgente

Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (125 commits)
  [CRYPTO] twofish: Merge common glue code
  [CRYPTO] hifn_795x: Fixup container_of() usage
  [CRYPTO] cast6: inline bloat--
  [CRYPTO] api: Set default CRYPTO_MINALIGN to unsigned long long
  [CRYPTO] tcrypt: Make xcbc available as a standalone test
  [CRYPTO] xcbc: Remove bogus hash/cipher test
  [CRYPTO] xcbc: Fix algorithm leak when block size check fails
  [CRYPTO] tcrypt: Zero axbuf in the right function
  [CRYPTO] padlock: Only reset the key once for each CBC and ECB operation
  [CRYPTO] api: Include sched.h for cond_resched in scatterwalk.h
  [CRYPTO] salsa20-asm: Remove unnecessary dependency on CRYPTO_SALSA20
  [CRYPTO] tcrypt: Add select of AEAD
  [CRYPTO] salsa20: Add x86-64 assembly version
  [CRYPTO] salsa20_i586: Salsa20 stream cipher algorithm (i586 version)
  [CRYPTO] gcm: Introduce rfc4106
  [CRYPTO] api: Show async type
  [CRYPTO] chainiv: Avoid lock spinning where possible
  [CRYPTO] seqiv: Add select AEAD in Kconfig
  [CRYPTO] scatterwalk: Handle zero nbytes in scatterwalk_map_and_copy
  [CRYPTO] null: Allow setkey on digest_null 
  ...
Linus Torvalds 17 anni fa
parent
commit
eba0e319c1
72 ha cambiato i file con 14377 aggiunte e 2768 eliminazioni
  1. 16 25
      Documentation/crypto/api-intro.txt
  2. 200 27
      arch/s390/crypto/aes_s390.c
  3. 8 4
      arch/x86/crypto/Makefile
  4. 43 46
      arch/x86/crypto/aes-i586-asm_32.S
  5. 34 34
      arch/x86/crypto/aes-x86_64-asm_64.S
  6. 0 515
      arch/x86/crypto/aes_32.c
  7. 0 336
      arch/x86/crypto/aes_64.c
  8. 57 0
      arch/x86/crypto/aes_glue.c
  9. 1114 0
      arch/x86/crypto/salsa20-i586-asm_32.S
  10. 920 0
      arch/x86/crypto/salsa20-x86_64-asm_64.S
  11. 129 0
      arch/x86/crypto/salsa20_glue.c
  12. 0 97
      arch/x86/crypto/twofish_64.c
  13. 4 4
      arch/x86/crypto/twofish_glue.c
  14. 91 6
      crypto/Kconfig
  15. 12 2
      crypto/Makefile
  16. 239 2
      crypto/ablkcipher.c
  17. 394 6
      crypto/aead.c
  18. 241 227
      crypto/aes_generic.c
  19. 63 2
      crypto/algapi.c
  20. 14 5
      crypto/api.c
  21. 213 121
      crypto/authenc.c
  22. 194 8
      crypto/blkcipher.c
  23. 394 741
      crypto/camellia.c
  24. 3 3
      crypto/cast6.c
  25. 25 84
      crypto/cbc.c
  26. 889 0
      crypto/ccm.c
  27. 331 0
      crypto/chainiv.c
  28. 4 2
      crypto/cryptd.c
  29. 60 10
      crypto/crypto_null.c
  30. 422 0
      crypto/ctr.c
  31. 6 11
      crypto/des_generic.c
  32. 1 3
      crypto/digest.c
  33. 264 0
      crypto/eseqiv.c
  34. 823 0
      crypto/gcm.c
  35. 2 1
      crypto/hmac.c
  36. 2 29
      crypto/internal.h
  37. 106 0
      crypto/lzo.c
  38. 24 81
      crypto/pcbc.c
  39. 255 0
      crypto/salsa20_generic.c
  40. 6 4
      crypto/scatterwalk.c
  41. 345 0
      crypto/seqiv.c
  42. 64 8
      crypto/sha256_generic.c
  43. 384 65
      crypto/tcrypt.c
  44. 2110 2
      crypto/tcrypt.h
  45. 30 66
      crypto/twofish_common.c
  46. 4 6
      crypto/xcbc.c
  47. 10 2
      drivers/char/hw_random/amd-rng.c
  48. 6 18
      drivers/char/hw_random/core.c
  49. 10 2
      drivers/char/hw_random/geode-rng.c
  50. 12 3
      drivers/char/hw_random/intel-rng.c
  51. 11 2
      drivers/char/hw_random/omap-rng.c
  52. 12 4
      drivers/char/hw_random/pasemi-rng.c
  53. 12 7
      drivers/char/hw_random/via-rng.c
  54. 11 0
      drivers/crypto/Kconfig
  55. 1 0
      drivers/crypto/Makefile
  56. 211 87
      drivers/crypto/geode-aes.c
  57. 41 3
      drivers/crypto/geode-aes.h
  58. 2838 0
      drivers/crypto/hifn_795x.c
  59. 16 8
      drivers/crypto/padlock-aes.c
  60. 105 0
      include/crypto/aead.h
  61. 31 0
      include/crypto/aes.h
  62. 21 10
      include/crypto/algapi.h
  63. 27 0
      include/crypto/authenc.h
  64. 20 0
      include/crypto/ctr.h
  65. 19 0
      include/crypto/des.h
  66. 80 0
      include/crypto/internal/aead.h
  67. 110 0
      include/crypto/internal/skcipher.h
  68. 42 3
      include/crypto/scatterwalk.h
  69. 12 0
      include/crypto/sha.h
  70. 110 0
      include/crypto/skcipher.h
  71. 68 35
      include/linux/crypto.h
  72. 1 1
      include/linux/hw_random.h

+ 16 - 25
Documentation/crypto/api-intro.txt

@@ -33,9 +33,16 @@ The idea is to make the user interface and algorithm registration API
 very simple, while hiding the core logic from both.  Many good ideas
 very simple, while hiding the core logic from both.  Many good ideas
 from existing APIs such as Cryptoapi and Nettle have been adapted for this.
 from existing APIs such as Cryptoapi and Nettle have been adapted for this.
 
 
-The API currently supports three types of transforms: Ciphers, Digests and
-Compressors.  The compression algorithms especially seem to be performing
-very well so far.
+The API currently supports five main types of transforms: AEAD (Authenticated
+Encryption with Associated Data), Block Ciphers, Ciphers, Compressors and
+Hashes.
+
+Please note that Block Ciphers is somewhat of a misnomer.  It is in fact
+meant to support all ciphers including stream ciphers.  The difference
+between Block Ciphers and Ciphers is that the latter operates on exactly
+one block while the former can operate on an arbitrary amount of data,
+subject to block size requirements (i.e., non-stream ciphers can only
+process multiples of blocks).
 
 
 Support for hardware crypto devices via an asynchronous interface is
 Support for hardware crypto devices via an asynchronous interface is
 under development.
 under development.
@@ -69,29 +76,12 @@ Here's an example of how to use the API:
 Many real examples are available in the regression test module (tcrypt.c).
 Many real examples are available in the regression test module (tcrypt.c).
 
 
 
 
-CONFIGURATION NOTES
-
-As Triple DES is part of the DES module, for those using modular builds,
-add the following line to /etc/modprobe.conf:
-
-  alias des3_ede des
-
-The Null algorithms reside in the crypto_null module, so these lines
-should also be added:
-
-  alias cipher_null crypto_null
-  alias digest_null crypto_null
-  alias compress_null crypto_null
-
-The SHA384 algorithm shares code within the SHA512 module, so you'll
-also need:
-  alias sha384 sha512
-
-
 DEVELOPER NOTES
 DEVELOPER NOTES
 
 
 Transforms may only be allocated in user context, and cryptographic
 Transforms may only be allocated in user context, and cryptographic
-methods may only be called from softirq and user contexts.
+methods may only be called from softirq and user contexts.  For
+transforms with a setkey method it too should only be called from
+user context.
 
 
 When using the API for ciphers, performance will be optimal if each
 When using the API for ciphers, performance will be optimal if each
 scatterlist contains data which is a multiple of the cipher's block
 scatterlist contains data which is a multiple of the cipher's block
@@ -130,8 +120,9 @@ might already be working on.
 BUGS
 BUGS
 
 
 Send bug reports to:
 Send bug reports to:
-Herbert Xu <herbert@gondor.apana.org.au>
-Cc: David S. Miller <davem@redhat.com>
+linux-crypto@vger.kernel.org
+Cc: Herbert Xu <herbert@gondor.apana.org.au>,
+    David S. Miller <davem@redhat.com>
 
 
 
 
 FURTHER INFORMATION
 FURTHER INFORMATION

+ 200 - 27
arch/s390/crypto/aes_s390.c

@@ -6,6 +6,7 @@
  * s390 Version:
  * s390 Version:
  *   Copyright IBM Corp. 2005,2007
  *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *   Author(s): Jan Glauber (jang@de.ibm.com)
+ *		Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback
  *
  *
  * Derived from "crypto/aes_generic.c"
  * Derived from "crypto/aes_generic.c"
  *
  *
@@ -16,17 +17,13 @@
  *
  *
  */
  */
 
 
+#include <crypto/aes.h>
 #include <crypto/algapi.h>
 #include <crypto/algapi.h>
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include "crypt_s390.h"
 #include "crypt_s390.h"
 
 
-#define AES_MIN_KEY_SIZE	16
-#define AES_MAX_KEY_SIZE	32
-
-/* data block size for all key lengths */
-#define AES_BLOCK_SIZE		16
-
 #define AES_KEYLEN_128		1
 #define AES_KEYLEN_128		1
 #define AES_KEYLEN_192		2
 #define AES_KEYLEN_192		2
 #define AES_KEYLEN_256		4
 #define AES_KEYLEN_256		4
@@ -39,45 +36,89 @@ struct s390_aes_ctx {
 	long enc;
 	long enc;
 	long dec;
 	long dec;
 	int key_len;
 	int key_len;
+	union {
+		struct crypto_blkcipher *blk;
+		struct crypto_cipher *cip;
+	} fallback;
 };
 };
 
 
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-		       unsigned int key_len)
+/*
+ * Check if the key_len is supported by the HW.
+ * Returns 0 if it is, a positive number if it is not and software fallback is
+ * required or a negative number in case the key size is not valid
+ */
+static int need_fallback(unsigned int key_len)
 {
 {
-	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
-	u32 *flags = &tfm->crt_flags;
-
 	switch (key_len) {
 	switch (key_len) {
 	case 16:
 	case 16:
 		if (!(keylen_flag & AES_KEYLEN_128))
 		if (!(keylen_flag & AES_KEYLEN_128))
-			goto fail;
+			return 1;
 		break;
 		break;
 	case 24:
 	case 24:
 		if (!(keylen_flag & AES_KEYLEN_192))
 		if (!(keylen_flag & AES_KEYLEN_192))
-			goto fail;
-
+			return 1;
 		break;
 		break;
 	case 32:
 	case 32:
 		if (!(keylen_flag & AES_KEYLEN_256))
 		if (!(keylen_flag & AES_KEYLEN_256))
-			goto fail;
+			return 1;
 		break;
 		break;
 	default:
 	default:
-		goto fail;
+		return -1;
 		break;
 		break;
 	}
 	}
+	return 0;
+}
+
+static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
+		unsigned int key_len)
+{
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+	int ret;
+
+	sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+			CRYPTO_TFM_REQ_MASK);
+
+	ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
+	if (ret) {
+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+		tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
+				CRYPTO_TFM_RES_MASK);
+	}
+	return ret;
+}
+
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len)
+{
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+	int ret;
+
+	ret = need_fallback(key_len);
+	if (ret < 0) {
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
 
 
 	sctx->key_len = key_len;
 	sctx->key_len = key_len;
-	memcpy(sctx->key, in_key, key_len);
-	return 0;
-fail:
-	*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-	return -EINVAL;
+	if (!ret) {
+		memcpy(sctx->key, in_key, key_len);
+		return 0;
+	}
+
+	return setkey_fallback_cip(tfm, in_key, key_len);
 }
 }
 
 
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
 
+	if (unlikely(need_fallback(sctx->key_len))) {
+		crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
+		return;
+	}
+
 	switch (sctx->key_len) {
 	switch (sctx->key_len) {
 	case 16:
 	case 16:
 		crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
 		crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
@@ -98,6 +139,11 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
 
+	if (unlikely(need_fallback(sctx->key_len))) {
+		crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
+		return;
+	}
+
 	switch (sctx->key_len) {
 	switch (sctx->key_len) {
 	case 16:
 	case 16:
 		crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
 		crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
@@ -114,6 +160,29 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 	}
 	}
 }
 }
 
 
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+	const char *name = tfm->__crt_alg->cra_name;
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+	sctx->fallback.cip = crypto_alloc_cipher(name, 0,
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+	if (IS_ERR(sctx->fallback.cip)) {
+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		return PTR_ERR(sctx->fallback.blk);
+	}
+
+	return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_cipher(sctx->fallback.cip);
+	sctx->fallback.cip = NULL;
+}
 
 
 static struct crypto_alg aes_alg = {
 static struct crypto_alg aes_alg = {
 	.cra_name		=	"aes",
 	.cra_name		=	"aes",
@@ -125,6 +194,8 @@ static struct crypto_alg aes_alg = {
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
+	.cra_init               =       fallback_init_cip,
+	.cra_exit               =       fallback_exit_cip,
 	.cra_u			=	{
 	.cra_u			=	{
 		.cipher = {
 		.cipher = {
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
@@ -136,10 +207,70 @@ static struct crypto_alg aes_alg = {
 	}
 	}
 };
 };
 
 
+static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key,
+		unsigned int len)
+{
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+	unsigned int ret;
+
+	sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+			CRYPTO_TFM_REQ_MASK);
+
+	ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len);
+	if (ret) {
+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+		tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
+				CRYPTO_TFM_RES_MASK);
+	}
+	return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	unsigned int ret;
+	struct crypto_blkcipher *tfm;
+	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+
+	tfm = desc->tfm;
+	desc->tfm = sctx->fallback.blk;
+
+	ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+	desc->tfm = tfm;
+	return ret;
+}
+
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	unsigned int ret;
+	struct crypto_blkcipher *tfm;
+	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+
+	tfm = desc->tfm;
+	desc->tfm = sctx->fallback.blk;
+
+	ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+	desc->tfm = tfm;
+	return ret;
+}
+
 static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 			   unsigned int key_len)
 			   unsigned int key_len)
 {
 {
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+	int ret;
+
+	ret = need_fallback(key_len);
+	if (ret > 0) {
+		sctx->key_len = key_len;
+		return setkey_fallback_blk(tfm, in_key, key_len);
+	}
 
 
 	switch (key_len) {
 	switch (key_len) {
 	case 16:
 	case 16:
@@ -188,6 +319,9 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 
 
+	if (unlikely(need_fallback(sctx->key_len)))
+		return fallback_blk_enc(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
 	return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
 }
 }
@@ -199,10 +333,37 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 
 
+	if (unlikely(need_fallback(sctx->key_len)))
+		return fallback_blk_dec(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
 	return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
 }
 }
 
 
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+	const char *name = tfm->__crt_alg->cra_name;
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+	sctx->fallback.blk = crypto_alloc_blkcipher(name, 0,
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+	if (IS_ERR(sctx->fallback.blk)) {
+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		return PTR_ERR(sctx->fallback.blk);
+	}
+
+	return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_blkcipher(sctx->fallback.blk);
+	sctx->fallback.blk = NULL;
+}
+
 static struct crypto_alg ecb_aes_alg = {
 static struct crypto_alg ecb_aes_alg = {
 	.cra_name		=	"ecb(aes)",
 	.cra_name		=	"ecb(aes)",
 	.cra_driver_name	=	"ecb-aes-s390",
 	.cra_driver_name	=	"ecb-aes-s390",
@@ -214,6 +375,8 @@ static struct crypto_alg ecb_aes_alg = {
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(ecb_aes_alg.cra_list),
 	.cra_list		=	LIST_HEAD_INIT(ecb_aes_alg.cra_list),
+	.cra_init		=	fallback_init_blk,
+	.cra_exit		=	fallback_exit_blk,
 	.cra_u			=	{
 	.cra_u			=	{
 		.blkcipher = {
 		.blkcipher = {
 			.min_keysize		=	AES_MIN_KEY_SIZE,
 			.min_keysize		=	AES_MIN_KEY_SIZE,
@@ -229,6 +392,13 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 			   unsigned int key_len)
 			   unsigned int key_len)
 {
 {
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+	int ret;
+
+	ret = need_fallback(key_len);
+	if (ret > 0) {
+		sctx->key_len = key_len;
+		return setkey_fallback_blk(tfm, in_key, key_len);
+	}
 
 
 	switch (key_len) {
 	switch (key_len) {
 	case 16:
 	case 16:
@@ -283,6 +453,9 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 
 
+	if (unlikely(need_fallback(sctx->key_len)))
+		return fallback_blk_enc(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
 	return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
 }
 }
@@ -294,6 +467,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 
 
+	if (unlikely(need_fallback(sctx->key_len)))
+		return fallback_blk_dec(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
 	return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
 }
 }
@@ -309,6 +485,8 @@ static struct crypto_alg cbc_aes_alg = {
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_type		=	&crypto_blkcipher_type,
 	.cra_module		=	THIS_MODULE,
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(cbc_aes_alg.cra_list),
 	.cra_list		=	LIST_HEAD_INIT(cbc_aes_alg.cra_list),
+	.cra_init		=	fallback_init_blk,
+	.cra_exit		=	fallback_exit_blk,
 	.cra_u			=	{
 	.cra_u			=	{
 		.blkcipher = {
 		.blkcipher = {
 			.min_keysize		=	AES_MIN_KEY_SIZE,
 			.min_keysize		=	AES_MIN_KEY_SIZE,
@@ -336,14 +514,10 @@ static int __init aes_init(void)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
 	/* z9 109 and z9 BC/EC only support 128 bit key length */
 	/* z9 109 and z9 BC/EC only support 128 bit key length */
-	if (keylen_flag == AES_KEYLEN_128) {
-		aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
-		ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
-		cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
+	if (keylen_flag == AES_KEYLEN_128)
 		printk(KERN_INFO
 		printk(KERN_INFO
 		       "aes_s390: hardware acceleration only available for"
 		       "aes_s390: hardware acceleration only available for"
 		       "128 bit keys\n");
 		       "128 bit keys\n");
-	}
 
 
 	ret = crypto_register_alg(&aes_alg);
 	ret = crypto_register_alg(&aes_alg);
 	if (ret)
 	if (ret)
@@ -382,4 +556,3 @@ MODULE_ALIAS("aes");
 
 
 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-

+ 8 - 4
arch/x86/crypto/Makefile

@@ -4,12 +4,16 @@
 
 
 obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
 obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
+obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
 
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
+obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
 
 
-aes-i586-y := aes-i586-asm_32.o aes_32.o
-twofish-i586-y := twofish-i586-asm_32.o twofish_32.o
+aes-i586-y := aes-i586-asm_32.o aes_glue.o
+twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
+salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
 
 
-aes-x86_64-y := aes-x86_64-asm_64.o aes_64.o
-twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_64.o
+aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
+twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
+salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o

+ 43 - 46
arch/x86/crypto/aes-i586-asm_32.S

@@ -46,9 +46,9 @@
 #define in_blk 16
 #define in_blk 16
 
 
 /* offsets in crypto_tfm structure */
 /* offsets in crypto_tfm structure */
-#define ekey (crypto_tfm_ctx_offset + 0)
-#define nrnd (crypto_tfm_ctx_offset + 256)
-#define dkey (crypto_tfm_ctx_offset + 260)
+#define klen (crypto_tfm_ctx_offset + 0)
+#define ekey (crypto_tfm_ctx_offset + 4)
+#define dkey (crypto_tfm_ctx_offset + 244)
 
 
 // register mapping for encrypt and decrypt subroutines
 // register mapping for encrypt and decrypt subroutines
 
 
@@ -221,8 +221,8 @@
 
 
 .global  aes_enc_blk
 .global  aes_enc_blk
 
 
-.extern  ft_tab
-.extern  fl_tab
+.extern  crypto_ft_tab
+.extern  crypto_fl_tab
 
 
 .align 4
 .align 4
 
 
@@ -236,7 +236,7 @@ aes_enc_blk:
 1:	push    %ebx
 1:	push    %ebx
 	mov     in_blk+4(%esp),%r2
 	mov     in_blk+4(%esp),%r2
 	push    %esi
 	push    %esi
-	mov     nrnd(%ebp),%r3   // number of rounds
+	mov     klen(%ebp),%r3   // key size
 	push    %edi
 	push    %edi
 #if ekey != 0
 #if ekey != 0
 	lea     ekey(%ebp),%ebp  // key pointer
 	lea     ekey(%ebp),%ebp  // key pointer
@@ -255,26 +255,26 @@ aes_enc_blk:
 
 
 	sub     $8,%esp		// space for register saves on stack
 	sub     $8,%esp		// space for register saves on stack
 	add     $16,%ebp	// increment to next round key
 	add     $16,%ebp	// increment to next round key
-	cmp     $12,%r3
+	cmp     $24,%r3
 	jb      4f		// 10 rounds for 128-bit key
 	jb      4f		// 10 rounds for 128-bit key
 	lea     32(%ebp),%ebp
 	lea     32(%ebp),%ebp
 	je      3f		// 12 rounds for 192-bit key
 	je      3f		// 12 rounds for 192-bit key
 	lea     32(%ebp),%ebp
 	lea     32(%ebp),%ebp
 
 
-2:	fwd_rnd1( -64(%ebp) ,ft_tab)	// 14 rounds for 256-bit key
-	fwd_rnd2( -48(%ebp) ,ft_tab)
-3:	fwd_rnd1( -32(%ebp) ,ft_tab)	// 12 rounds for 192-bit key
-	fwd_rnd2( -16(%ebp) ,ft_tab)
-4:	fwd_rnd1(    (%ebp) ,ft_tab)	// 10 rounds for 128-bit key
-	fwd_rnd2( +16(%ebp) ,ft_tab)
-	fwd_rnd1( +32(%ebp) ,ft_tab)
-	fwd_rnd2( +48(%ebp) ,ft_tab)
-	fwd_rnd1( +64(%ebp) ,ft_tab)
-	fwd_rnd2( +80(%ebp) ,ft_tab)
-	fwd_rnd1( +96(%ebp) ,ft_tab)
-	fwd_rnd2(+112(%ebp) ,ft_tab)
-	fwd_rnd1(+128(%ebp) ,ft_tab)
-	fwd_rnd2(+144(%ebp) ,fl_tab)	// last round uses a different table
+2:	fwd_rnd1( -64(%ebp), crypto_ft_tab)	// 14 rounds for 256-bit key
+	fwd_rnd2( -48(%ebp), crypto_ft_tab)
+3:	fwd_rnd1( -32(%ebp), crypto_ft_tab)	// 12 rounds for 192-bit key
+	fwd_rnd2( -16(%ebp), crypto_ft_tab)
+4:	fwd_rnd1(    (%ebp), crypto_ft_tab)	// 10 rounds for 128-bit key
+	fwd_rnd2( +16(%ebp), crypto_ft_tab)
+	fwd_rnd1( +32(%ebp), crypto_ft_tab)
+	fwd_rnd2( +48(%ebp), crypto_ft_tab)
+	fwd_rnd1( +64(%ebp), crypto_ft_tab)
+	fwd_rnd2( +80(%ebp), crypto_ft_tab)
+	fwd_rnd1( +96(%ebp), crypto_ft_tab)
+	fwd_rnd2(+112(%ebp), crypto_ft_tab)
+	fwd_rnd1(+128(%ebp), crypto_ft_tab)
+	fwd_rnd2(+144(%ebp), crypto_fl_tab)	// last round uses a different table
 
 
 // move final values to the output array.  CAUTION: the 
 // move final values to the output array.  CAUTION: the 
 // order of these assigns rely on the register mappings
 // order of these assigns rely on the register mappings
@@ -297,8 +297,8 @@ aes_enc_blk:
 
 
 .global  aes_dec_blk
 .global  aes_dec_blk
 
 
-.extern  it_tab
-.extern  il_tab
+.extern  crypto_it_tab
+.extern  crypto_il_tab
 
 
 .align 4
 .align 4
 
 
@@ -312,14 +312,11 @@ aes_dec_blk:
 1:	push    %ebx
 1:	push    %ebx
 	mov     in_blk+4(%esp),%r2
 	mov     in_blk+4(%esp),%r2
 	push    %esi
 	push    %esi
-	mov     nrnd(%ebp),%r3   // number of rounds
+	mov     klen(%ebp),%r3   // key size
 	push    %edi
 	push    %edi
 #if dkey != 0
 #if dkey != 0
 	lea     dkey(%ebp),%ebp  // key pointer
 	lea     dkey(%ebp),%ebp  // key pointer
 #endif
 #endif
-	mov     %r3,%r0
-	shl     $4,%r0
-	add     %r0,%ebp
 	
 	
 // input four columns and xor in first round key
 // input four columns and xor in first round key
 
 
@@ -333,27 +330,27 @@ aes_dec_blk:
 	xor     12(%ebp),%r5
 	xor     12(%ebp),%r5
 
 
 	sub     $8,%esp		// space for register saves on stack
 	sub     $8,%esp		// space for register saves on stack
-	sub     $16,%ebp	// increment to next round key
-	cmp     $12,%r3
+	add     $16,%ebp	// increment to next round key
+	cmp     $24,%r3
 	jb      4f		// 10 rounds for 128-bit key
 	jb      4f		// 10 rounds for 128-bit key
-	lea     -32(%ebp),%ebp
+	lea     32(%ebp),%ebp
 	je      3f		// 12 rounds for 192-bit key
 	je      3f		// 12 rounds for 192-bit key
-	lea     -32(%ebp),%ebp
-
-2:	inv_rnd1( +64(%ebp), it_tab)	// 14 rounds for 256-bit key
-	inv_rnd2( +48(%ebp), it_tab)
-3:	inv_rnd1( +32(%ebp), it_tab)	// 12 rounds for 192-bit key
-	inv_rnd2( +16(%ebp), it_tab)
-4:	inv_rnd1(    (%ebp), it_tab)	// 10 rounds for 128-bit key
-	inv_rnd2( -16(%ebp), it_tab)
-	inv_rnd1( -32(%ebp), it_tab)
-	inv_rnd2( -48(%ebp), it_tab)
-	inv_rnd1( -64(%ebp), it_tab)
-	inv_rnd2( -80(%ebp), it_tab)
-	inv_rnd1( -96(%ebp), it_tab)
-	inv_rnd2(-112(%ebp), it_tab)
-	inv_rnd1(-128(%ebp), it_tab)
-	inv_rnd2(-144(%ebp), il_tab)	// last round uses a different table
+	lea     32(%ebp),%ebp
+
+2:	inv_rnd1( -64(%ebp), crypto_it_tab)	// 14 rounds for 256-bit key
+	inv_rnd2( -48(%ebp), crypto_it_tab)
+3:	inv_rnd1( -32(%ebp), crypto_it_tab)	// 12 rounds for 192-bit key
+	inv_rnd2( -16(%ebp), crypto_it_tab)
+4:	inv_rnd1(    (%ebp), crypto_it_tab)	// 10 rounds for 128-bit key
+	inv_rnd2( +16(%ebp), crypto_it_tab)
+	inv_rnd1( +32(%ebp), crypto_it_tab)
+	inv_rnd2( +48(%ebp), crypto_it_tab)
+	inv_rnd1( +64(%ebp), crypto_it_tab)
+	inv_rnd2( +80(%ebp), crypto_it_tab)
+	inv_rnd1( +96(%ebp), crypto_it_tab)
+	inv_rnd2(+112(%ebp), crypto_it_tab)
+	inv_rnd1(+128(%ebp), crypto_it_tab)
+	inv_rnd2(+144(%ebp), crypto_il_tab)	// last round uses a different table
 
 
 // move final values to the output array.  CAUTION: the 
 // move final values to the output array.  CAUTION: the 
 // order of these assigns rely on the register mappings
 // order of these assigns rely on the register mappings

+ 34 - 34
arch/x86/crypto/aes-x86_64-asm_64.S

@@ -8,10 +8,10 @@
  * including this sentence is retained in full.
  * including this sentence is retained in full.
  */
  */
 
 
-.extern aes_ft_tab
-.extern aes_it_tab
-.extern aes_fl_tab
-.extern aes_il_tab
+.extern crypto_ft_tab
+.extern crypto_it_tab
+.extern crypto_fl_tab
+.extern crypto_il_tab
 
 
 .text
 .text
 
 
@@ -56,13 +56,13 @@
 	.align	8;			\
 	.align	8;			\
 FUNC:	movq	r1,r2;			\
 FUNC:	movq	r1,r2;			\
 	movq	r3,r4;			\
 	movq	r3,r4;			\
-	leaq	BASE+KEY+52(r8),r9;	\
+	leaq	BASE+KEY+48+4(r8),r9;	\
 	movq	r10,r11;		\
 	movq	r10,r11;		\
 	movl	(r7),r5 ## E;		\
 	movl	(r7),r5 ## E;		\
 	movl	4(r7),r1 ## E;		\
 	movl	4(r7),r1 ## E;		\
 	movl	8(r7),r6 ## E;		\
 	movl	8(r7),r6 ## E;		\
 	movl	12(r7),r7 ## E;		\
 	movl	12(r7),r7 ## E;		\
-	movl	BASE(r8),r10 ## E;	\
+	movl	BASE+0(r8),r10 ## E;	\
 	xorl	-48(r9),r5 ## E;	\
 	xorl	-48(r9),r5 ## E;	\
 	xorl	-44(r9),r1 ## E;	\
 	xorl	-44(r9),r1 ## E;	\
 	xorl	-40(r9),r6 ## E;	\
 	xorl	-40(r9),r6 ## E;	\
@@ -154,37 +154,37 @@ FUNC:	movq	r1,r2;			\
 /* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */
 /* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */
 
 
 	entry(aes_enc_blk,0,enc128,enc192)
 	entry(aes_enc_blk,0,enc128,enc192)
-	encrypt_round(aes_ft_tab,-96)
-	encrypt_round(aes_ft_tab,-80)
-enc192:	encrypt_round(aes_ft_tab,-64)
-	encrypt_round(aes_ft_tab,-48)
-enc128:	encrypt_round(aes_ft_tab,-32)
-	encrypt_round(aes_ft_tab,-16)
-	encrypt_round(aes_ft_tab,  0)
-	encrypt_round(aes_ft_tab, 16)
-	encrypt_round(aes_ft_tab, 32)
-	encrypt_round(aes_ft_tab, 48)
-	encrypt_round(aes_ft_tab, 64)
-	encrypt_round(aes_ft_tab, 80)
-	encrypt_round(aes_ft_tab, 96)
-	encrypt_final(aes_fl_tab,112)
+	encrypt_round(crypto_ft_tab,-96)
+	encrypt_round(crypto_ft_tab,-80)
+enc192:	encrypt_round(crypto_ft_tab,-64)
+	encrypt_round(crypto_ft_tab,-48)
+enc128:	encrypt_round(crypto_ft_tab,-32)
+	encrypt_round(crypto_ft_tab,-16)
+	encrypt_round(crypto_ft_tab,  0)
+	encrypt_round(crypto_ft_tab, 16)
+	encrypt_round(crypto_ft_tab, 32)
+	encrypt_round(crypto_ft_tab, 48)
+	encrypt_round(crypto_ft_tab, 64)
+	encrypt_round(crypto_ft_tab, 80)
+	encrypt_round(crypto_ft_tab, 96)
+	encrypt_final(crypto_fl_tab,112)
 	return
 	return
 
 
 /* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */
 /* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */
 
 
 	entry(aes_dec_blk,240,dec128,dec192)
 	entry(aes_dec_blk,240,dec128,dec192)
-	decrypt_round(aes_it_tab,-96)
-	decrypt_round(aes_it_tab,-80)
-dec192:	decrypt_round(aes_it_tab,-64)
-	decrypt_round(aes_it_tab,-48)
-dec128:	decrypt_round(aes_it_tab,-32)
-	decrypt_round(aes_it_tab,-16)
-	decrypt_round(aes_it_tab,  0)
-	decrypt_round(aes_it_tab, 16)
-	decrypt_round(aes_it_tab, 32)
-	decrypt_round(aes_it_tab, 48)
-	decrypt_round(aes_it_tab, 64)
-	decrypt_round(aes_it_tab, 80)
-	decrypt_round(aes_it_tab, 96)
-	decrypt_final(aes_il_tab,112)
+	decrypt_round(crypto_it_tab,-96)
+	decrypt_round(crypto_it_tab,-80)
+dec192:	decrypt_round(crypto_it_tab,-64)
+	decrypt_round(crypto_it_tab,-48)
+dec128:	decrypt_round(crypto_it_tab,-32)
+	decrypt_round(crypto_it_tab,-16)
+	decrypt_round(crypto_it_tab,  0)
+	decrypt_round(crypto_it_tab, 16)
+	decrypt_round(crypto_it_tab, 32)
+	decrypt_round(crypto_it_tab, 48)
+	decrypt_round(crypto_it_tab, 64)
+	decrypt_round(crypto_it_tab, 80)
+	decrypt_round(crypto_it_tab, 96)
+	decrypt_final(crypto_il_tab,112)
 	return
 	return

+ 0 - 515
arch/x86/crypto/aes_32.c

@@ -1,515 +0,0 @@
-/* 
- * 
- * Glue Code for optimized 586 assembler version of AES
- *
- * Copyright (c) 2002, Dr Brian Gladman <>, Worcester, UK.
- * All rights reserved.
- *
- * LICENSE TERMS
- *
- * The free distribution and use of this software in both source and binary
- * form is allowed (with or without changes) provided that:
- *
- *   1. distributions of this source code include the above copyright
- *      notice, this list of conditions and the following disclaimer;
- *
- *   2. distributions in binary form include the above copyright
- *      notice, this list of conditions and the following disclaimer
- *      in the documentation and/or other associated materials;
- *
- *   3. the copyright holder's name is not used to endorse products
- *      built using this software without specific written permission.
- *
- * ALTERNATIVELY, provided that this notice is retained in full, this product
- * may be distributed under the terms of the GNU General Public License (GPL),
- * in which case the provisions of the GPL apply INSTEAD OF those given above.
- *
- * DISCLAIMER
- *
- * This software is provided 'as is' with no explicit or implied warranties
- * in respect of its properties, including, but not limited to, correctness
- * and/or fitness for purpose.
- *
- * Copyright (c) 2003, Adam J. Richter <adam@yggdrasil.com> (conversion to
- * 2.5 API).
- * Copyright (c) 2003, 2004 Fruhwirth Clemens <clemens@endorphin.org>
- * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
- *
- */
-
-#include <asm/byteorder.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-#include <linux/linkage.h>
-
-asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-#define AES_MIN_KEY_SIZE	16
-#define AES_MAX_KEY_SIZE	32
-#define AES_BLOCK_SIZE		16
-#define AES_KS_LENGTH		4 * AES_BLOCK_SIZE
-#define RC_LENGTH		29
-
-struct aes_ctx {
-	u32 ekey[AES_KS_LENGTH];
-	u32 rounds;
-	u32 dkey[AES_KS_LENGTH];
-};
-
-#define WPOLY 0x011b
-#define bytes2word(b0, b1, b2, b3)  \
-	(((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0))
-
-/* define the finite field multiplies required for Rijndael */
-#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
-#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
-#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
-#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
-#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
-#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
-#define fi(x) ((x) ?   pow[255 - log[x]]: 0)
-
-static inline u32 upr(u32 x, int n)
-{
-	return (x << 8 * n) | (x >> (32 - 8 * n));
-}
-
-static inline u8 bval(u32 x, int n)
-{
-	return x >> 8 * n;
-}
-
-/* The forward and inverse affine transformations used in the S-box */
-#define fwd_affine(x) \
-	(w = (u32)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(u8)(w^(w>>8)))
-
-#define inv_affine(x) \
-	(w = (u32)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(u8)(w^(w>>8)))
-
-static u32 rcon_tab[RC_LENGTH];
-
-u32 ft_tab[4][256];
-u32 fl_tab[4][256];
-static u32 im_tab[4][256];
-u32 il_tab[4][256];
-u32 it_tab[4][256];
-
-static void gen_tabs(void)
-{
-	u32 i, w;
-	u8 pow[512], log[256];
-
-	/*
-	 * log and power tables for GF(2^8) finite field with
-	 * WPOLY as modular polynomial - the simplest primitive
-	 * root is 0x03, used here to generate the tables.
-	 */
-	i = 0; w = 1; 
-	
-	do {
-		pow[i] = (u8)w;
-		pow[i + 255] = (u8)w;
-		log[w] = (u8)i++;
-		w ^=  (w << 1) ^ (w & 0x80 ? WPOLY : 0);
-	} while (w != 1);
-	
-	for(i = 0, w = 1; i < RC_LENGTH; ++i) {
-		rcon_tab[i] = bytes2word(w, 0, 0, 0);
-		w = f2(w);
-	}
-
-	for(i = 0; i < 256; ++i) {
-		u8 b;
-		
-		b = fwd_affine(fi((u8)i));
-		w = bytes2word(f2(b), b, b, f3(b));
-
-		/* tables for a normal encryption round */
-		ft_tab[0][i] = w;
-		ft_tab[1][i] = upr(w, 1);
-		ft_tab[2][i] = upr(w, 2);
-		ft_tab[3][i] = upr(w, 3);
-		w = bytes2word(b, 0, 0, 0);
-		
-		/*
-		 * tables for last encryption round
-		 * (may also be used in the key schedule)
-		 */
-		fl_tab[0][i] = w;
-		fl_tab[1][i] = upr(w, 1);
-		fl_tab[2][i] = upr(w, 2);
-		fl_tab[3][i] = upr(w, 3);
-		
-		b = fi(inv_affine((u8)i));
-		w = bytes2word(fe(b), f9(b), fd(b), fb(b));
-
-		/* tables for the inverse mix column operation  */
-		im_tab[0][b] = w;
-		im_tab[1][b] = upr(w, 1);
-		im_tab[2][b] = upr(w, 2);
-		im_tab[3][b] = upr(w, 3);
-
-		/* tables for a normal decryption round */
-		it_tab[0][i] = w;
-		it_tab[1][i] = upr(w,1);
-		it_tab[2][i] = upr(w,2);
-		it_tab[3][i] = upr(w,3);
-
-		w = bytes2word(b, 0, 0, 0);
-		
-		/* tables for last decryption round */
-		il_tab[0][i] = w;
-		il_tab[1][i] = upr(w,1);
-		il_tab[2][i] = upr(w,2);
-		il_tab[3][i] = upr(w,3);
-    }
-}
-
-#define four_tables(x,tab,vf,rf,c)		\
-(	tab[0][bval(vf(x,0,c),rf(0,c))]	^	\
-	tab[1][bval(vf(x,1,c),rf(1,c))] ^	\
-	tab[2][bval(vf(x,2,c),rf(2,c))] ^	\
-	tab[3][bval(vf(x,3,c),rf(3,c))]		\
-)
-
-#define vf1(x,r,c)  (x)
-#define rf1(r,c)    (r)
-#define rf2(r,c)    ((r-c)&3)
-
-#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0)
-#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c)
-
-#define ff(x) inv_mcol(x)
-
-#define ke4(k,i)							\
-{									\
-	k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i];		\
-	k[4*(i)+5] = ss[1] ^= ss[0];					\
-	k[4*(i)+6] = ss[2] ^= ss[1];					\
-	k[4*(i)+7] = ss[3] ^= ss[2];					\
-}
-
-#define kel4(k,i)							\
-{									\
-	k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i];		\
-	k[4*(i)+5] = ss[1] ^= ss[0];					\
-	k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2];	\
-}
-
-#define ke6(k,i)							\
-{									\
-	k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];		\
-	k[6*(i)+ 7] = ss[1] ^= ss[0];					\
-	k[6*(i)+ 8] = ss[2] ^= ss[1];					\
-	k[6*(i)+ 9] = ss[3] ^= ss[2];					\
-	k[6*(i)+10] = ss[4] ^= ss[3];					\
-	k[6*(i)+11] = ss[5] ^= ss[4];					\
-}
-
-#define kel6(k,i)							\
-{									\
-	k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];		\
-	k[6*(i)+ 7] = ss[1] ^= ss[0];					\
-	k[6*(i)+ 8] = ss[2] ^= ss[1];					\
-	k[6*(i)+ 9] = ss[3] ^= ss[2];					\
-}
-
-#define ke8(k,i)							\
-{									\
-	k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];		\
-	k[8*(i)+ 9] = ss[1] ^= ss[0];					\
-	k[8*(i)+10] = ss[2] ^= ss[1];					\
-	k[8*(i)+11] = ss[3] ^= ss[2];					\
-	k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0);				\
-	k[8*(i)+13] = ss[5] ^= ss[4];					\
-	k[8*(i)+14] = ss[6] ^= ss[5];					\
-	k[8*(i)+15] = ss[7] ^= ss[6];					\
-}
-
-#define kel8(k,i)							\
-{									\
-	k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];		\
-	k[8*(i)+ 9] = ss[1] ^= ss[0];					\
-	k[8*(i)+10] = ss[2] ^= ss[1];					\
-	k[8*(i)+11] = ss[3] ^= ss[2];					\
-}
-
-#define kdf4(k,i)							\
-{									\
-	ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3];				\
-	ss[1] = ss[1] ^ ss[3];						\
-	ss[2] = ss[2] ^ ss[3];						\
-	ss[3] = ss[3];							\
-	ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];			\
-	ss[i % 4] ^= ss[4];						\
-	ss[4] ^= k[4*(i)];						\
-	k[4*(i)+4] = ff(ss[4]);						\
-	ss[4] ^= k[4*(i)+1];						\
-	k[4*(i)+5] = ff(ss[4]);						\
-	ss[4] ^= k[4*(i)+2];						\
-	k[4*(i)+6] = ff(ss[4]);						\
-	ss[4] ^= k[4*(i)+3];						\
-	k[4*(i)+7] = ff(ss[4]);						\
-}
-
-#define kd4(k,i)							\
-{									\
-	ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];			\
-	ss[i % 4] ^= ss[4];						\
-	ss[4] = ff(ss[4]);						\
-	k[4*(i)+4] = ss[4] ^= k[4*(i)];					\
-	k[4*(i)+5] = ss[4] ^= k[4*(i)+1];				\
-	k[4*(i)+6] = ss[4] ^= k[4*(i)+2];				\
-	k[4*(i)+7] = ss[4] ^= k[4*(i)+3];				\
-}
-
-#define kdl4(k,i)							\
-{									\
-	ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i];			\
-	ss[i % 4] ^= ss[4];						\
-	k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3];			\
-	k[4*(i)+5] = ss[1] ^ ss[3];					\
-	k[4*(i)+6] = ss[0];						\
-	k[4*(i)+7] = ss[1];						\
-}
-
-#define kdf6(k,i)							\
-{									\
-	ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];				\
-	k[6*(i)+ 6] = ff(ss[0]);					\
-	ss[1] ^= ss[0];							\
-	k[6*(i)+ 7] = ff(ss[1]);					\
-	ss[2] ^= ss[1];							\
-	k[6*(i)+ 8] = ff(ss[2]);					\
-	ss[3] ^= ss[2];							\
-	k[6*(i)+ 9] = ff(ss[3]);					\
-	ss[4] ^= ss[3];							\
-	k[6*(i)+10] = ff(ss[4]);					\
-	ss[5] ^= ss[4];							\
-	k[6*(i)+11] = ff(ss[5]);					\
-}
-
-#define kd6(k,i)							\
-{									\
-	ss[6] = ls_box(ss[5],3) ^ rcon_tab[i];				\
-	ss[0] ^= ss[6]; ss[6] = ff(ss[6]);				\
-	k[6*(i)+ 6] = ss[6] ^= k[6*(i)];				\
-	ss[1] ^= ss[0];							\
-	k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1];				\
-	ss[2] ^= ss[1];							\
-	k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2];				\
-	ss[3] ^= ss[2];							\
-	k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3];				\
-	ss[4] ^= ss[3];							\
-	k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4];				\
-	ss[5] ^= ss[4];							\
-	k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5];				\
-}
-
-#define kdl6(k,i)							\
-{									\
-	ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i];				\
-	k[6*(i)+ 6] = ss[0];						\
-	ss[1] ^= ss[0];							\
-	k[6*(i)+ 7] = ss[1];						\
-	ss[2] ^= ss[1];							\
-	k[6*(i)+ 8] = ss[2];						\
-	ss[3] ^= ss[2];							\
-	k[6*(i)+ 9] = ss[3];						\
-}
-
-#define kdf8(k,i)							\
-{									\
-	ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];				\
-	k[8*(i)+ 8] = ff(ss[0]);					\
-	ss[1] ^= ss[0];							\
-	k[8*(i)+ 9] = ff(ss[1]);					\
-	ss[2] ^= ss[1];							\
-	k[8*(i)+10] = ff(ss[2]);					\
-	ss[3] ^= ss[2];							\
-	k[8*(i)+11] = ff(ss[3]);					\
-	ss[4] ^= ls_box(ss[3],0);					\
-	k[8*(i)+12] = ff(ss[4]);					\
-	ss[5] ^= ss[4];							\
-	k[8*(i)+13] = ff(ss[5]);					\
-	ss[6] ^= ss[5];							\
-	k[8*(i)+14] = ff(ss[6]);					\
-	ss[7] ^= ss[6];							\
-	k[8*(i)+15] = ff(ss[7]);					\
-}
-
-#define kd8(k,i)							\
-{									\
-	u32 __g = ls_box(ss[7],3) ^ rcon_tab[i];			\
-	ss[0] ^= __g;							\
-	__g = ff(__g);							\
-	k[8*(i)+ 8] = __g ^= k[8*(i)];					\
-	ss[1] ^= ss[0];							\
-	k[8*(i)+ 9] = __g ^= k[8*(i)+ 1];				\
-	ss[2] ^= ss[1];							\
-	k[8*(i)+10] = __g ^= k[8*(i)+ 2];				\
-	ss[3] ^= ss[2];							\
-	k[8*(i)+11] = __g ^= k[8*(i)+ 3];				\
-	__g = ls_box(ss[3],0);						\
-	ss[4] ^= __g;							\
-	__g = ff(__g);							\
-	k[8*(i)+12] = __g ^= k[8*(i)+ 4];				\
-	ss[5] ^= ss[4];							\
-	k[8*(i)+13] = __g ^= k[8*(i)+ 5];				\
-	ss[6] ^= ss[5];							\
-	k[8*(i)+14] = __g ^= k[8*(i)+ 6];				\
-	ss[7] ^= ss[6];							\
-	k[8*(i)+15] = __g ^= k[8*(i)+ 7];				\
-}
-
-#define kdl8(k,i)							\
-{									\
-	ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i];				\
-	k[8*(i)+ 8] = ss[0];						\
-	ss[1] ^= ss[0];							\
-	k[8*(i)+ 9] = ss[1];						\
-	ss[2] ^= ss[1];							\
-	k[8*(i)+10] = ss[2];						\
-	ss[3] ^= ss[2];							\
-	k[8*(i)+11] = ss[3];						\
-}
-
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-		       unsigned int key_len)
-{
-	int i;
-	u32 ss[8];
-	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
-	const __le32 *key = (const __le32 *)in_key;
-	u32 *flags = &tfm->crt_flags;
-
-	/* encryption schedule */
-	
-	ctx->ekey[0] = ss[0] = le32_to_cpu(key[0]);
-	ctx->ekey[1] = ss[1] = le32_to_cpu(key[1]);
-	ctx->ekey[2] = ss[2] = le32_to_cpu(key[2]);
-	ctx->ekey[3] = ss[3] = le32_to_cpu(key[3]);
-
-	switch(key_len) {
-	case 16:
-		for (i = 0; i < 9; i++)
-			ke4(ctx->ekey, i);
-		kel4(ctx->ekey, 9);
-		ctx->rounds = 10;
-		break;
-		
-	case 24:
-		ctx->ekey[4] = ss[4] = le32_to_cpu(key[4]);
-		ctx->ekey[5] = ss[5] = le32_to_cpu(key[5]);
-		for (i = 0; i < 7; i++)
-			ke6(ctx->ekey, i);
-		kel6(ctx->ekey, 7); 
-		ctx->rounds = 12;
-		break;
-
-	case 32:
-		ctx->ekey[4] = ss[4] = le32_to_cpu(key[4]);
-		ctx->ekey[5] = ss[5] = le32_to_cpu(key[5]);
-		ctx->ekey[6] = ss[6] = le32_to_cpu(key[6]);
-		ctx->ekey[7] = ss[7] = le32_to_cpu(key[7]);
-		for (i = 0; i < 6; i++)
-			ke8(ctx->ekey, i);
-		kel8(ctx->ekey, 6);
-		ctx->rounds = 14;
-		break;
-
-	default:
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-		return -EINVAL;
-	}
-	
-	/* decryption schedule */
-	
-	ctx->dkey[0] = ss[0] = le32_to_cpu(key[0]);
-	ctx->dkey[1] = ss[1] = le32_to_cpu(key[1]);
-	ctx->dkey[2] = ss[2] = le32_to_cpu(key[2]);
-	ctx->dkey[3] = ss[3] = le32_to_cpu(key[3]);
-
-	switch (key_len) {
-	case 16:
-		kdf4(ctx->dkey, 0);
-		for (i = 1; i < 9; i++)
-			kd4(ctx->dkey, i);
-		kdl4(ctx->dkey, 9);
-		break;
-		
-	case 24:
-		ctx->dkey[4] = ff(ss[4] = le32_to_cpu(key[4]));
-		ctx->dkey[5] = ff(ss[5] = le32_to_cpu(key[5]));
-		kdf6(ctx->dkey, 0);
-		for (i = 1; i < 7; i++)
-			kd6(ctx->dkey, i);
-		kdl6(ctx->dkey, 7);
-		break;
-
-	case 32:
-		ctx->dkey[4] = ff(ss[4] = le32_to_cpu(key[4]));
-		ctx->dkey[5] = ff(ss[5] = le32_to_cpu(key[5]));
-		ctx->dkey[6] = ff(ss[6] = le32_to_cpu(key[6]));
-		ctx->dkey[7] = ff(ss[7] = le32_to_cpu(key[7]));
-		kdf8(ctx->dkey, 0);
-		for (i = 1; i < 6; i++)
-			kd8(ctx->dkey, i);
-		kdl8(ctx->dkey, 6);
-		break;
-	}
-	return 0;
-}
-
-static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	aes_enc_blk(tfm, dst, src);
-}
-
-static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	aes_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg aes_alg = {
-	.cra_name		=	"aes",
-	.cra_driver_name	=	"aes-i586",
-	.cra_priority		=	200,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct aes_ctx),
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
-	.cra_u			=	{
-		.cipher = {
-			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
-			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
-			.cia_setkey	   	= 	aes_set_key,
-			.cia_encrypt	 	=	aes_encrypt,
-			.cia_decrypt	  	=	aes_decrypt
-		}
-	}
-};
-
-static int __init aes_init(void)
-{
-	gen_tabs();
-	return crypto_register_alg(&aes_alg);
-}
-
-static void __exit aes_fini(void)
-{
-	crypto_unregister_alg(&aes_alg);
-}
-
-module_init(aes_init);
-module_exit(aes_fini);
-
-MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, i586 asm optimized");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Fruhwirth Clemens, James Morris, Brian Gladman, Adam Richter");
-MODULE_ALIAS("aes");

+ 0 - 336
arch/x86/crypto/aes_64.c

@@ -1,336 +0,0 @@
-/*
- * Cryptographic API.
- *
- * AES Cipher Algorithm.
- *
- * Based on Brian Gladman's code.
- *
- * Linux developers:
- *  Alexander Kjeldaas <astor@fast.no>
- *  Herbert Valerio Riedel <hvr@hvrlab.org>
- *  Kyle McMartin <kyle@debian.org>
- *  Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
- *  Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler)
- *
- * 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.
- *
- * ---------------------------------------------------------------------------
- * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
- * All rights reserved.
- *
- * LICENSE TERMS
- *
- * The free distribution and use of this software in both source and binary
- * form is allowed (with or without changes) provided that:
- *
- *   1. distributions of this source code include the above copyright
- *      notice, this list of conditions and the following disclaimer;
- *
- *   2. distributions in binary form include the above copyright
- *      notice, this list of conditions and the following disclaimer
- *      in the documentation and/or other associated materials;
- *
- *   3. the copyright holder's name is not used to endorse products
- *      built using this software without specific written permission.
- *
- * ALTERNATIVELY, provided that this notice is retained in full, this product
- * may be distributed under the terms of the GNU General Public License (GPL),
- * in which case the provisions of the GPL apply INSTEAD OF those given above.
- *
- * DISCLAIMER
- *
- * This software is provided 'as is' with no explicit or implied warranties
- * in respect of its properties, including, but not limited to, correctness
- * and/or fitness for purpose.
- * ---------------------------------------------------------------------------
- */
-
-/* Some changes from the Gladman version:
-    s/RIJNDAEL(e_key)/E_KEY/g
-    s/RIJNDAEL(d_key)/D_KEY/g
-*/
-
-#include <asm/byteorder.h>
-#include <linux/bitops.h>
-#include <linux/crypto.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-#define AES_MIN_KEY_SIZE	16
-#define AES_MAX_KEY_SIZE	32
-
-#define AES_BLOCK_SIZE		16
-
-/*
- * #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))
- */
-static inline u8 byte(const u32 x, const unsigned n)
-{
-	return x >> (n << 3);
-}
-
-struct aes_ctx
-{
-	u32 key_length;
-	u32 buf[120];
-};
-
-#define E_KEY (&ctx->buf[0])
-#define D_KEY (&ctx->buf[60])
-
-static u8 pow_tab[256] __initdata;
-static u8 log_tab[256] __initdata;
-static u8 sbx_tab[256] __initdata;
-static u8 isb_tab[256] __initdata;
-static u32 rco_tab[10];
-u32 aes_ft_tab[4][256];
-u32 aes_it_tab[4][256];
-
-u32 aes_fl_tab[4][256];
-u32 aes_il_tab[4][256];
-
-static inline u8 f_mult(u8 a, u8 b)
-{
-	u8 aa = log_tab[a], cc = aa + log_tab[b];
-
-	return pow_tab[cc + (cc < aa ? 1 : 0)];
-}
-
-#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0)
-
-#define ls_box(x)				\
-	(aes_fl_tab[0][byte(x, 0)] ^		\
-	 aes_fl_tab[1][byte(x, 1)] ^		\
-	 aes_fl_tab[2][byte(x, 2)] ^		\
-	 aes_fl_tab[3][byte(x, 3)])
-
-static void __init gen_tabs(void)
-{
-	u32 i, t;
-	u8 p, q;
-
-	/* log and power tables for GF(2**8) finite field with
-	   0x011b as modular polynomial - the simplest primitive
-	   root is 0x03, used here to generate the tables */
-
-	for (i = 0, p = 1; i < 256; ++i) {
-		pow_tab[i] = (u8)p;
-		log_tab[p] = (u8)i;
-
-		p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
-	}
-
-	log_tab[1] = 0;
-
-	for (i = 0, p = 1; i < 10; ++i) {
-		rco_tab[i] = p;
-
-		p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
-	}
-
-	for (i = 0; i < 256; ++i) {
-		p = (i ? pow_tab[255 - log_tab[i]] : 0);
-		q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
-		p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
-		sbx_tab[i] = p;
-		isb_tab[p] = (u8)i;
-	}
-
-	for (i = 0; i < 256; ++i) {
-		p = sbx_tab[i];
-
-		t = p;
-		aes_fl_tab[0][i] = t;
-		aes_fl_tab[1][i] = rol32(t, 8);
-		aes_fl_tab[2][i] = rol32(t, 16);
-		aes_fl_tab[3][i] = rol32(t, 24);
-
-		t = ((u32)ff_mult(2, p)) |
-		    ((u32)p << 8) |
-		    ((u32)p << 16) | ((u32)ff_mult(3, p) << 24);
-
-		aes_ft_tab[0][i] = t;
-		aes_ft_tab[1][i] = rol32(t, 8);
-		aes_ft_tab[2][i] = rol32(t, 16);
-		aes_ft_tab[3][i] = rol32(t, 24);
-
-		p = isb_tab[i];
-
-		t = p;
-		aes_il_tab[0][i] = t;
-		aes_il_tab[1][i] = rol32(t, 8);
-		aes_il_tab[2][i] = rol32(t, 16);
-		aes_il_tab[3][i] = rol32(t, 24);
-
-		t = ((u32)ff_mult(14, p)) |
-		    ((u32)ff_mult(9, p) << 8) |
-		    ((u32)ff_mult(13, p) << 16) |
-		    ((u32)ff_mult(11, p) << 24);
-
-		aes_it_tab[0][i] = t;
-		aes_it_tab[1][i] = rol32(t, 8);
-		aes_it_tab[2][i] = rol32(t, 16);
-		aes_it_tab[3][i] = rol32(t, 24);
-	}
-}
-
-#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
-
-#define imix_col(y, x)			\
-	u    = star_x(x);		\
-	v    = star_x(u);		\
-	w    = star_x(v);		\
-	t    = w ^ (x);			\
-	(y)  = u ^ v ^ w;		\
-	(y) ^= ror32(u ^ t,  8) ^	\
-	       ror32(v ^ t, 16) ^	\
-	       ror32(t, 24)
-
-/* initialise the key schedule from the user supplied key */
-
-#define loop4(i)					\
-{							\
-	t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];	\
-	t ^= E_KEY[4 * i];     E_KEY[4 * i + 4] = t;	\
-	t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t;	\
-	t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t;	\
-	t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t;	\
-}
-
-#define loop6(i)					\
-{							\
-	t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];	\
-	t ^= E_KEY[6 * i];     E_KEY[6 * i + 6] = t;	\
-	t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t;	\
-	t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t;	\
-	t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t;	\
-	t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t;	\
-	t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t;	\
-}
-
-#define loop8(i)					\
-{							\
-	t = ror32(t,  8); ; t = ls_box(t) ^ rco_tab[i];	\
-	t ^= E_KEY[8 * i];     E_KEY[8 * i + 8] = t;	\
-	t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t;	\
-	t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t;	\
-	t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t;	\
-	t  = E_KEY[8 * i + 4] ^ ls_box(t);		\
-	E_KEY[8 * i + 12] = t;				\
-	t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t;	\
-	t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t;	\
-	t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;	\
-}
-
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-		       unsigned int key_len)
-{
-	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
-	const __le32 *key = (const __le32 *)in_key;
-	u32 *flags = &tfm->crt_flags;
-	u32 i, j, t, u, v, w;
-
-	if (key_len % 8) {
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-		return -EINVAL;
-	}
-
-	ctx->key_length = key_len;
-
-	D_KEY[key_len + 24] = E_KEY[0] = le32_to_cpu(key[0]);
-	D_KEY[key_len + 25] = E_KEY[1] = le32_to_cpu(key[1]);
-	D_KEY[key_len + 26] = E_KEY[2] = le32_to_cpu(key[2]);
-	D_KEY[key_len + 27] = E_KEY[3] = le32_to_cpu(key[3]);
-
-	switch (key_len) {
-	case 16:
-		t = E_KEY[3];
-		for (i = 0; i < 10; ++i)
-			loop4(i);
-		break;
-
-	case 24:
-		E_KEY[4] = le32_to_cpu(key[4]);
-		t = E_KEY[5] = le32_to_cpu(key[5]);
-		for (i = 0; i < 8; ++i)
-			loop6 (i);
-		break;
-
-	case 32:
-		E_KEY[4] = le32_to_cpu(key[4]);
-		E_KEY[5] = le32_to_cpu(key[5]);
-		E_KEY[6] = le32_to_cpu(key[6]);
-		t = E_KEY[7] = le32_to_cpu(key[7]);
-		for (i = 0; i < 7; ++i)
-			loop8(i);
-		break;
-	}
-
-	D_KEY[0] = E_KEY[key_len + 24];
-	D_KEY[1] = E_KEY[key_len + 25];
-	D_KEY[2] = E_KEY[key_len + 26];
-	D_KEY[3] = E_KEY[key_len + 27];
-
-	for (i = 4; i < key_len + 24; ++i) {
-		j = key_len + 24 - (i & ~3) + (i & 3);
-		imix_col(D_KEY[j], E_KEY[i]);
-	}
-
-	return 0;
-}
-
-asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
-asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
-
-static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	aes_enc_blk(tfm, dst, src);
-}
-
-static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	aes_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg aes_alg = {
-	.cra_name		=	"aes",
-	.cra_driver_name	=	"aes-x86_64",
-	.cra_priority		=	200,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct aes_ctx),
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
-	.cra_u			=	{
-		.cipher = {
-			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
-			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
-			.cia_setkey	   	= 	aes_set_key,
-			.cia_encrypt	 	=	aes_encrypt,
-			.cia_decrypt	  	=	aes_decrypt
-		}
-	}
-};
-
-static int __init aes_init(void)
-{
-	gen_tabs();
-	return crypto_register_alg(&aes_alg);
-}
-
-static void __exit aes_fini(void)
-{
-	crypto_unregister_alg(&aes_alg);
-}
-
-module_init(aes_init);
-module_exit(aes_fini);
-
-MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("aes");

+ 57 - 0
arch/x86/crypto/aes_glue.c

@@ -0,0 +1,57 @@
+/*
+ * Glue Code for the asm optimized version of the AES Cipher Algorithm
+ *
+ */
+
+#include <crypto/aes.h>
+
+asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	aes_enc_blk(tfm, dst, src);
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	aes_dec_blk(tfm, dst, src);
+}
+
+static struct crypto_alg aes_alg = {
+	.cra_name		= "aes",
+	.cra_driver_name	= "aes-asm",
+	.cra_priority		= 200,
+	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct crypto_aes_ctx),
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(aes_alg.cra_list),
+	.cra_u	= {
+		.cipher	= {
+			.cia_min_keysize	= AES_MIN_KEY_SIZE,
+			.cia_max_keysize	= AES_MAX_KEY_SIZE,
+			.cia_setkey		= crypto_aes_set_key,
+			.cia_encrypt		= aes_encrypt,
+			.cia_decrypt		= aes_decrypt
+		}
+	}
+};
+
+static int __init aes_init(void)
+{
+	return crypto_register_alg(&aes_alg);
+}
+
+static void __exit aes_fini(void)
+{
+	crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, asm optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("aes");
+MODULE_ALIAS("aes-asm");

+ 1114 - 0
arch/x86/crypto/salsa20-i586-asm_32.S

@@ -0,0 +1,1114 @@
+# salsa20_pm.s version 20051229
+# D. J. Bernstein
+# Public domain.
+
+# enter ECRYPT_encrypt_bytes
+.text
+.p2align 5
+.globl ECRYPT_encrypt_bytes
+ECRYPT_encrypt_bytes:
+	mov	%esp,%eax
+	and	$31,%eax
+	add	$256,%eax
+	sub	%eax,%esp
+	# eax_stack = eax
+	movl	%eax,80(%esp)
+	# ebx_stack = ebx
+	movl	%ebx,84(%esp)
+	# esi_stack = esi
+	movl	%esi,88(%esp)
+	# edi_stack = edi
+	movl	%edi,92(%esp)
+	# ebp_stack = ebp
+	movl	%ebp,96(%esp)
+	# x = arg1
+	movl	4(%esp,%eax),%edx
+	# m = arg2
+	movl	8(%esp,%eax),%esi
+	# out = arg3
+	movl	12(%esp,%eax),%edi
+	# bytes = arg4
+	movl	16(%esp,%eax),%ebx
+	# bytes -= 0
+	sub	$0,%ebx
+	# goto done if unsigned<=
+	jbe	._done
+._start:
+	# in0 = *(uint32 *) (x + 0)
+	movl	0(%edx),%eax
+	# in1 = *(uint32 *) (x + 4)
+	movl	4(%edx),%ecx
+	# in2 = *(uint32 *) (x + 8)
+	movl	8(%edx),%ebp
+	# j0 = in0
+	movl	%eax,164(%esp)
+	# in3 = *(uint32 *) (x + 12)
+	movl	12(%edx),%eax
+	# j1 = in1
+	movl	%ecx,168(%esp)
+	# in4 = *(uint32 *) (x + 16)
+	movl	16(%edx),%ecx
+	# j2 = in2
+	movl	%ebp,172(%esp)
+	# in5 = *(uint32 *) (x + 20)
+	movl	20(%edx),%ebp
+	# j3 = in3
+	movl	%eax,176(%esp)
+	# in6 = *(uint32 *) (x + 24)
+	movl	24(%edx),%eax
+	# j4 = in4
+	movl	%ecx,180(%esp)
+	# in7 = *(uint32 *) (x + 28)
+	movl	28(%edx),%ecx
+	# j5 = in5
+	movl	%ebp,184(%esp)
+	# in8 = *(uint32 *) (x + 32)
+	movl	32(%edx),%ebp
+	# j6 = in6
+	movl	%eax,188(%esp)
+	# in9 = *(uint32 *) (x + 36)
+	movl	36(%edx),%eax
+	# j7 = in7
+	movl	%ecx,192(%esp)
+	# in10 = *(uint32 *) (x + 40)
+	movl	40(%edx),%ecx
+	# j8 = in8
+	movl	%ebp,196(%esp)
+	# in11 = *(uint32 *) (x + 44)
+	movl	44(%edx),%ebp
+	# j9 = in9
+	movl	%eax,200(%esp)
+	# in12 = *(uint32 *) (x + 48)
+	movl	48(%edx),%eax
+	# j10 = in10
+	movl	%ecx,204(%esp)
+	# in13 = *(uint32 *) (x + 52)
+	movl	52(%edx),%ecx
+	# j11 = in11
+	movl	%ebp,208(%esp)
+	# in14 = *(uint32 *) (x + 56)
+	movl	56(%edx),%ebp
+	# j12 = in12
+	movl	%eax,212(%esp)
+	# in15 = *(uint32 *) (x + 60)
+	movl	60(%edx),%eax
+	# j13 = in13
+	movl	%ecx,216(%esp)
+	# j14 = in14
+	movl	%ebp,220(%esp)
+	# j15 = in15
+	movl	%eax,224(%esp)
+	# x_backup = x
+	movl	%edx,64(%esp)
+._bytesatleast1:
+	#   bytes - 64
+	cmp	$64,%ebx
+	#   goto nocopy if unsigned>=
+	jae	._nocopy
+	#     ctarget = out
+	movl	%edi,228(%esp)
+	#     out = &tmp
+	leal	0(%esp),%edi
+	#     i = bytes
+	mov	%ebx,%ecx
+	#     while (i) { *out++ = *m++; --i }
+	rep	movsb
+	#     out = &tmp
+	leal	0(%esp),%edi
+	#     m = &tmp
+	leal	0(%esp),%esi
+._nocopy:
+	#   out_backup = out
+	movl	%edi,72(%esp)
+	#   m_backup = m
+	movl	%esi,68(%esp)
+	#   bytes_backup = bytes
+	movl	%ebx,76(%esp)
+	#   in0 = j0
+	movl	164(%esp),%eax
+	#   in1 = j1
+	movl	168(%esp),%ecx
+	#   in2 = j2
+	movl	172(%esp),%edx
+	#   in3 = j3
+	movl	176(%esp),%ebx
+	#   x0 = in0
+	movl	%eax,100(%esp)
+	#   x1 = in1
+	movl	%ecx,104(%esp)
+	#   x2 = in2
+	movl	%edx,108(%esp)
+	#   x3 = in3
+	movl	%ebx,112(%esp)
+	#   in4 = j4
+	movl	180(%esp),%eax
+	#   in5 = j5
+	movl	184(%esp),%ecx
+	#   in6 = j6
+	movl	188(%esp),%edx
+	#   in7 = j7
+	movl	192(%esp),%ebx
+	#   x4 = in4
+	movl	%eax,116(%esp)
+	#   x5 = in5
+	movl	%ecx,120(%esp)
+	#   x6 = in6
+	movl	%edx,124(%esp)
+	#   x7 = in7
+	movl	%ebx,128(%esp)
+	#   in8 = j8
+	movl	196(%esp),%eax
+	#   in9 = j9
+	movl	200(%esp),%ecx
+	#   in10 = j10
+	movl	204(%esp),%edx
+	#   in11 = j11
+	movl	208(%esp),%ebx
+	#   x8 = in8
+	movl	%eax,132(%esp)
+	#   x9 = in9
+	movl	%ecx,136(%esp)
+	#   x10 = in10
+	movl	%edx,140(%esp)
+	#   x11 = in11
+	movl	%ebx,144(%esp)
+	#   in12 = j12
+	movl	212(%esp),%eax
+	#   in13 = j13
+	movl	216(%esp),%ecx
+	#   in14 = j14
+	movl	220(%esp),%edx
+	#   in15 = j15
+	movl	224(%esp),%ebx
+	#   x12 = in12
+	movl	%eax,148(%esp)
+	#   x13 = in13
+	movl	%ecx,152(%esp)
+	#   x14 = in14
+	movl	%edx,156(%esp)
+	#   x15 = in15
+	movl	%ebx,160(%esp)
+	#   i = 20
+	mov	$20,%ebp
+	# p = x0
+	movl	100(%esp),%eax
+	# s = x5
+	movl	120(%esp),%ecx
+	# t = x10
+	movl	140(%esp),%edx
+	# w = x15
+	movl	160(%esp),%ebx
+._mainloop:
+	# x0 = p
+	movl	%eax,100(%esp)
+	# 				x10 = t
+	movl	%edx,140(%esp)
+	# p += x12
+	addl	148(%esp),%eax
+	# 		x5 = s
+	movl	%ecx,120(%esp)
+	# 				t += x6
+	addl	124(%esp),%edx
+	# 						x15 = w
+	movl	%ebx,160(%esp)
+	# 		r = x1
+	movl	104(%esp),%esi
+	# 		r += s
+	add	%ecx,%esi
+	# 						v = x11
+	movl	144(%esp),%edi
+	# 						v += w
+	add	%ebx,%edi
+	# p <<<= 7
+	rol	$7,%eax
+	# p ^= x4
+	xorl	116(%esp),%eax
+	# 				t <<<= 7
+	rol	$7,%edx
+	# 				t ^= x14
+	xorl	156(%esp),%edx
+	# 		r <<<= 7
+	rol	$7,%esi
+	# 		r ^= x9
+	xorl	136(%esp),%esi
+	# 						v <<<= 7
+	rol	$7,%edi
+	# 						v ^= x3
+	xorl	112(%esp),%edi
+	# x4 = p
+	movl	%eax,116(%esp)
+	# 				x14 = t
+	movl	%edx,156(%esp)
+	# p += x0
+	addl	100(%esp),%eax
+	# 		x9 = r
+	movl	%esi,136(%esp)
+	# 				t += x10
+	addl	140(%esp),%edx
+	# 						x3 = v
+	movl	%edi,112(%esp)
+	# p <<<= 9
+	rol	$9,%eax
+	# p ^= x8
+	xorl	132(%esp),%eax
+	# 				t <<<= 9
+	rol	$9,%edx
+	# 				t ^= x2
+	xorl	108(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 9
+	rol	$9,%ecx
+	# 		s ^= x13
+	xorl	152(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 9
+	rol	$9,%ebx
+	# 						w ^= x7
+	xorl	128(%esp),%ebx
+	# x8 = p
+	movl	%eax,132(%esp)
+	# 				x2 = t
+	movl	%edx,108(%esp)
+	# p += x4
+	addl	116(%esp),%eax
+	# 		x13 = s
+	movl	%ecx,152(%esp)
+	# 				t += x14
+	addl	156(%esp),%edx
+	# 						x7 = w
+	movl	%ebx,128(%esp)
+	# p <<<= 13
+	rol	$13,%eax
+	# p ^= x12
+	xorl	148(%esp),%eax
+	# 				t <<<= 13
+	rol	$13,%edx
+	# 				t ^= x6
+	xorl	124(%esp),%edx
+	# 		r += s
+	add	%ecx,%esi
+	# 		r <<<= 13
+	rol	$13,%esi
+	# 		r ^= x1
+	xorl	104(%esp),%esi
+	# 						v += w
+	add	%ebx,%edi
+	# 						v <<<= 13
+	rol	$13,%edi
+	# 						v ^= x11
+	xorl	144(%esp),%edi
+	# x12 = p
+	movl	%eax,148(%esp)
+	# 				x6 = t
+	movl	%edx,124(%esp)
+	# p += x8
+	addl	132(%esp),%eax
+	# 		x1 = r
+	movl	%esi,104(%esp)
+	# 				t += x2
+	addl	108(%esp),%edx
+	# 						x11 = v
+	movl	%edi,144(%esp)
+	# p <<<= 18
+	rol	$18,%eax
+	# p ^= x0
+	xorl	100(%esp),%eax
+	# 				t <<<= 18
+	rol	$18,%edx
+	# 				t ^= x10
+	xorl	140(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 18
+	rol	$18,%ecx
+	# 		s ^= x5
+	xorl	120(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 18
+	rol	$18,%ebx
+	# 						w ^= x15
+	xorl	160(%esp),%ebx
+	# x0 = p
+	movl	%eax,100(%esp)
+	# 				x10 = t
+	movl	%edx,140(%esp)
+	# p += x3
+	addl	112(%esp),%eax
+	# p <<<= 7
+	rol	$7,%eax
+	# 		x5 = s
+	movl	%ecx,120(%esp)
+	# 				t += x9
+	addl	136(%esp),%edx
+	# 						x15 = w
+	movl	%ebx,160(%esp)
+	# 		r = x4
+	movl	116(%esp),%esi
+	# 		r += s
+	add	%ecx,%esi
+	# 						v = x14
+	movl	156(%esp),%edi
+	# 						v += w
+	add	%ebx,%edi
+	# p ^= x1
+	xorl	104(%esp),%eax
+	# 				t <<<= 7
+	rol	$7,%edx
+	# 				t ^= x11
+	xorl	144(%esp),%edx
+	# 		r <<<= 7
+	rol	$7,%esi
+	# 		r ^= x6
+	xorl	124(%esp),%esi
+	# 						v <<<= 7
+	rol	$7,%edi
+	# 						v ^= x12
+	xorl	148(%esp),%edi
+	# x1 = p
+	movl	%eax,104(%esp)
+	# 				x11 = t
+	movl	%edx,144(%esp)
+	# p += x0
+	addl	100(%esp),%eax
+	# 		x6 = r
+	movl	%esi,124(%esp)
+	# 				t += x10
+	addl	140(%esp),%edx
+	# 						x12 = v
+	movl	%edi,148(%esp)
+	# p <<<= 9
+	rol	$9,%eax
+	# p ^= x2
+	xorl	108(%esp),%eax
+	# 				t <<<= 9
+	rol	$9,%edx
+	# 				t ^= x8
+	xorl	132(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 9
+	rol	$9,%ecx
+	# 		s ^= x7
+	xorl	128(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 9
+	rol	$9,%ebx
+	# 						w ^= x13
+	xorl	152(%esp),%ebx
+	# x2 = p
+	movl	%eax,108(%esp)
+	# 				x8 = t
+	movl	%edx,132(%esp)
+	# p += x1
+	addl	104(%esp),%eax
+	# 		x7 = s
+	movl	%ecx,128(%esp)
+	# 				t += x11
+	addl	144(%esp),%edx
+	# 						x13 = w
+	movl	%ebx,152(%esp)
+	# p <<<= 13
+	rol	$13,%eax
+	# p ^= x3
+	xorl	112(%esp),%eax
+	# 				t <<<= 13
+	rol	$13,%edx
+	# 				t ^= x9
+	xorl	136(%esp),%edx
+	# 		r += s
+	add	%ecx,%esi
+	# 		r <<<= 13
+	rol	$13,%esi
+	# 		r ^= x4
+	xorl	116(%esp),%esi
+	# 						v += w
+	add	%ebx,%edi
+	# 						v <<<= 13
+	rol	$13,%edi
+	# 						v ^= x14
+	xorl	156(%esp),%edi
+	# x3 = p
+	movl	%eax,112(%esp)
+	# 				x9 = t
+	movl	%edx,136(%esp)
+	# p += x2
+	addl	108(%esp),%eax
+	# 		x4 = r
+	movl	%esi,116(%esp)
+	# 				t += x8
+	addl	132(%esp),%edx
+	# 						x14 = v
+	movl	%edi,156(%esp)
+	# p <<<= 18
+	rol	$18,%eax
+	# p ^= x0
+	xorl	100(%esp),%eax
+	# 				t <<<= 18
+	rol	$18,%edx
+	# 				t ^= x10
+	xorl	140(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 18
+	rol	$18,%ecx
+	# 		s ^= x5
+	xorl	120(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 18
+	rol	$18,%ebx
+	# 						w ^= x15
+	xorl	160(%esp),%ebx
+	# x0 = p
+	movl	%eax,100(%esp)
+	# 				x10 = t
+	movl	%edx,140(%esp)
+	# p += x12
+	addl	148(%esp),%eax
+	# 		x5 = s
+	movl	%ecx,120(%esp)
+	# 				t += x6
+	addl	124(%esp),%edx
+	# 						x15 = w
+	movl	%ebx,160(%esp)
+	# 		r = x1
+	movl	104(%esp),%esi
+	# 		r += s
+	add	%ecx,%esi
+	# 						v = x11
+	movl	144(%esp),%edi
+	# 						v += w
+	add	%ebx,%edi
+	# p <<<= 7
+	rol	$7,%eax
+	# p ^= x4
+	xorl	116(%esp),%eax
+	# 				t <<<= 7
+	rol	$7,%edx
+	# 				t ^= x14
+	xorl	156(%esp),%edx
+	# 		r <<<= 7
+	rol	$7,%esi
+	# 		r ^= x9
+	xorl	136(%esp),%esi
+	# 						v <<<= 7
+	rol	$7,%edi
+	# 						v ^= x3
+	xorl	112(%esp),%edi
+	# x4 = p
+	movl	%eax,116(%esp)
+	# 				x14 = t
+	movl	%edx,156(%esp)
+	# p += x0
+	addl	100(%esp),%eax
+	# 		x9 = r
+	movl	%esi,136(%esp)
+	# 				t += x10
+	addl	140(%esp),%edx
+	# 						x3 = v
+	movl	%edi,112(%esp)
+	# p <<<= 9
+	rol	$9,%eax
+	# p ^= x8
+	xorl	132(%esp),%eax
+	# 				t <<<= 9
+	rol	$9,%edx
+	# 				t ^= x2
+	xorl	108(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 9
+	rol	$9,%ecx
+	# 		s ^= x13
+	xorl	152(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 9
+	rol	$9,%ebx
+	# 						w ^= x7
+	xorl	128(%esp),%ebx
+	# x8 = p
+	movl	%eax,132(%esp)
+	# 				x2 = t
+	movl	%edx,108(%esp)
+	# p += x4
+	addl	116(%esp),%eax
+	# 		x13 = s
+	movl	%ecx,152(%esp)
+	# 				t += x14
+	addl	156(%esp),%edx
+	# 						x7 = w
+	movl	%ebx,128(%esp)
+	# p <<<= 13
+	rol	$13,%eax
+	# p ^= x12
+	xorl	148(%esp),%eax
+	# 				t <<<= 13
+	rol	$13,%edx
+	# 				t ^= x6
+	xorl	124(%esp),%edx
+	# 		r += s
+	add	%ecx,%esi
+	# 		r <<<= 13
+	rol	$13,%esi
+	# 		r ^= x1
+	xorl	104(%esp),%esi
+	# 						v += w
+	add	%ebx,%edi
+	# 						v <<<= 13
+	rol	$13,%edi
+	# 						v ^= x11
+	xorl	144(%esp),%edi
+	# x12 = p
+	movl	%eax,148(%esp)
+	# 				x6 = t
+	movl	%edx,124(%esp)
+	# p += x8
+	addl	132(%esp),%eax
+	# 		x1 = r
+	movl	%esi,104(%esp)
+	# 				t += x2
+	addl	108(%esp),%edx
+	# 						x11 = v
+	movl	%edi,144(%esp)
+	# p <<<= 18
+	rol	$18,%eax
+	# p ^= x0
+	xorl	100(%esp),%eax
+	# 				t <<<= 18
+	rol	$18,%edx
+	# 				t ^= x10
+	xorl	140(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 18
+	rol	$18,%ecx
+	# 		s ^= x5
+	xorl	120(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 18
+	rol	$18,%ebx
+	# 						w ^= x15
+	xorl	160(%esp),%ebx
+	# x0 = p
+	movl	%eax,100(%esp)
+	# 				x10 = t
+	movl	%edx,140(%esp)
+	# p += x3
+	addl	112(%esp),%eax
+	# p <<<= 7
+	rol	$7,%eax
+	# 		x5 = s
+	movl	%ecx,120(%esp)
+	# 				t += x9
+	addl	136(%esp),%edx
+	# 						x15 = w
+	movl	%ebx,160(%esp)
+	# 		r = x4
+	movl	116(%esp),%esi
+	# 		r += s
+	add	%ecx,%esi
+	# 						v = x14
+	movl	156(%esp),%edi
+	# 						v += w
+	add	%ebx,%edi
+	# p ^= x1
+	xorl	104(%esp),%eax
+	# 				t <<<= 7
+	rol	$7,%edx
+	# 				t ^= x11
+	xorl	144(%esp),%edx
+	# 		r <<<= 7
+	rol	$7,%esi
+	# 		r ^= x6
+	xorl	124(%esp),%esi
+	# 						v <<<= 7
+	rol	$7,%edi
+	# 						v ^= x12
+	xorl	148(%esp),%edi
+	# x1 = p
+	movl	%eax,104(%esp)
+	# 				x11 = t
+	movl	%edx,144(%esp)
+	# p += x0
+	addl	100(%esp),%eax
+	# 		x6 = r
+	movl	%esi,124(%esp)
+	# 				t += x10
+	addl	140(%esp),%edx
+	# 						x12 = v
+	movl	%edi,148(%esp)
+	# p <<<= 9
+	rol	$9,%eax
+	# p ^= x2
+	xorl	108(%esp),%eax
+	# 				t <<<= 9
+	rol	$9,%edx
+	# 				t ^= x8
+	xorl	132(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 9
+	rol	$9,%ecx
+	# 		s ^= x7
+	xorl	128(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 9
+	rol	$9,%ebx
+	# 						w ^= x13
+	xorl	152(%esp),%ebx
+	# x2 = p
+	movl	%eax,108(%esp)
+	# 				x8 = t
+	movl	%edx,132(%esp)
+	# p += x1
+	addl	104(%esp),%eax
+	# 		x7 = s
+	movl	%ecx,128(%esp)
+	# 				t += x11
+	addl	144(%esp),%edx
+	# 						x13 = w
+	movl	%ebx,152(%esp)
+	# p <<<= 13
+	rol	$13,%eax
+	# p ^= x3
+	xorl	112(%esp),%eax
+	# 				t <<<= 13
+	rol	$13,%edx
+	# 				t ^= x9
+	xorl	136(%esp),%edx
+	# 		r += s
+	add	%ecx,%esi
+	# 		r <<<= 13
+	rol	$13,%esi
+	# 		r ^= x4
+	xorl	116(%esp),%esi
+	# 						v += w
+	add	%ebx,%edi
+	# 						v <<<= 13
+	rol	$13,%edi
+	# 						v ^= x14
+	xorl	156(%esp),%edi
+	# x3 = p
+	movl	%eax,112(%esp)
+	# 				x9 = t
+	movl	%edx,136(%esp)
+	# p += x2
+	addl	108(%esp),%eax
+	# 		x4 = r
+	movl	%esi,116(%esp)
+	# 				t += x8
+	addl	132(%esp),%edx
+	# 						x14 = v
+	movl	%edi,156(%esp)
+	# p <<<= 18
+	rol	$18,%eax
+	# p ^= x0
+	xorl	100(%esp),%eax
+	# 				t <<<= 18
+	rol	$18,%edx
+	# 				t ^= x10
+	xorl	140(%esp),%edx
+	# 		s += r
+	add	%esi,%ecx
+	# 		s <<<= 18
+	rol	$18,%ecx
+	# 		s ^= x5
+	xorl	120(%esp),%ecx
+	# 						w += v
+	add	%edi,%ebx
+	# 						w <<<= 18
+	rol	$18,%ebx
+	# 						w ^= x15
+	xorl	160(%esp),%ebx
+	# i -= 4
+	sub	$4,%ebp
+	# goto mainloop if unsigned >
+	ja	._mainloop
+	# x0 = p
+	movl	%eax,100(%esp)
+	# x5 = s
+	movl	%ecx,120(%esp)
+	# x10 = t
+	movl	%edx,140(%esp)
+	# x15 = w
+	movl	%ebx,160(%esp)
+	#   out = out_backup
+	movl	72(%esp),%edi
+	#   m = m_backup
+	movl	68(%esp),%esi
+	#   in0 = x0
+	movl	100(%esp),%eax
+	#   in1 = x1
+	movl	104(%esp),%ecx
+	#   in0 += j0
+	addl	164(%esp),%eax
+	#   in1 += j1
+	addl	168(%esp),%ecx
+	#   in0 ^= *(uint32 *) (m + 0)
+	xorl	0(%esi),%eax
+	#   in1 ^= *(uint32 *) (m + 4)
+	xorl	4(%esi),%ecx
+	#   *(uint32 *) (out + 0) = in0
+	movl	%eax,0(%edi)
+	#   *(uint32 *) (out + 4) = in1
+	movl	%ecx,4(%edi)
+	#   in2 = x2
+	movl	108(%esp),%eax
+	#   in3 = x3
+	movl	112(%esp),%ecx
+	#   in2 += j2
+	addl	172(%esp),%eax
+	#   in3 += j3
+	addl	176(%esp),%ecx
+	#   in2 ^= *(uint32 *) (m + 8)
+	xorl	8(%esi),%eax
+	#   in3 ^= *(uint32 *) (m + 12)
+	xorl	12(%esi),%ecx
+	#   *(uint32 *) (out + 8) = in2
+	movl	%eax,8(%edi)
+	#   *(uint32 *) (out + 12) = in3
+	movl	%ecx,12(%edi)
+	#   in4 = x4
+	movl	116(%esp),%eax
+	#   in5 = x5
+	movl	120(%esp),%ecx
+	#   in4 += j4
+	addl	180(%esp),%eax
+	#   in5 += j5
+	addl	184(%esp),%ecx
+	#   in4 ^= *(uint32 *) (m + 16)
+	xorl	16(%esi),%eax
+	#   in5 ^= *(uint32 *) (m + 20)
+	xorl	20(%esi),%ecx
+	#   *(uint32 *) (out + 16) = in4
+	movl	%eax,16(%edi)
+	#   *(uint32 *) (out + 20) = in5
+	movl	%ecx,20(%edi)
+	#   in6 = x6
+	movl	124(%esp),%eax
+	#   in7 = x7
+	movl	128(%esp),%ecx
+	#   in6 += j6
+	addl	188(%esp),%eax
+	#   in7 += j7
+	addl	192(%esp),%ecx
+	#   in6 ^= *(uint32 *) (m + 24)
+	xorl	24(%esi),%eax
+	#   in7 ^= *(uint32 *) (m + 28)
+	xorl	28(%esi),%ecx
+	#   *(uint32 *) (out + 24) = in6
+	movl	%eax,24(%edi)
+	#   *(uint32 *) (out + 28) = in7
+	movl	%ecx,28(%edi)
+	#   in8 = x8
+	movl	132(%esp),%eax
+	#   in9 = x9
+	movl	136(%esp),%ecx
+	#   in8 += j8
+	addl	196(%esp),%eax
+	#   in9 += j9
+	addl	200(%esp),%ecx
+	#   in8 ^= *(uint32 *) (m + 32)
+	xorl	32(%esi),%eax
+	#   in9 ^= *(uint32 *) (m + 36)
+	xorl	36(%esi),%ecx
+	#   *(uint32 *) (out + 32) = in8
+	movl	%eax,32(%edi)
+	#   *(uint32 *) (out + 36) = in9
+	movl	%ecx,36(%edi)
+	#   in10 = x10
+	movl	140(%esp),%eax
+	#   in11 = x11
+	movl	144(%esp),%ecx
+	#   in10 += j10
+	addl	204(%esp),%eax
+	#   in11 += j11
+	addl	208(%esp),%ecx
+	#   in10 ^= *(uint32 *) (m + 40)
+	xorl	40(%esi),%eax
+	#   in11 ^= *(uint32 *) (m + 44)
+	xorl	44(%esi),%ecx
+	#   *(uint32 *) (out + 40) = in10
+	movl	%eax,40(%edi)
+	#   *(uint32 *) (out + 44) = in11
+	movl	%ecx,44(%edi)
+	#   in12 = x12
+	movl	148(%esp),%eax
+	#   in13 = x13
+	movl	152(%esp),%ecx
+	#   in12 += j12
+	addl	212(%esp),%eax
+	#   in13 += j13
+	addl	216(%esp),%ecx
+	#   in12 ^= *(uint32 *) (m + 48)
+	xorl	48(%esi),%eax
+	#   in13 ^= *(uint32 *) (m + 52)
+	xorl	52(%esi),%ecx
+	#   *(uint32 *) (out + 48) = in12
+	movl	%eax,48(%edi)
+	#   *(uint32 *) (out + 52) = in13
+	movl	%ecx,52(%edi)
+	#   in14 = x14
+	movl	156(%esp),%eax
+	#   in15 = x15
+	movl	160(%esp),%ecx
+	#   in14 += j14
+	addl	220(%esp),%eax
+	#   in15 += j15
+	addl	224(%esp),%ecx
+	#   in14 ^= *(uint32 *) (m + 56)
+	xorl	56(%esi),%eax
+	#   in15 ^= *(uint32 *) (m + 60)
+	xorl	60(%esi),%ecx
+	#   *(uint32 *) (out + 56) = in14
+	movl	%eax,56(%edi)
+	#   *(uint32 *) (out + 60) = in15
+	movl	%ecx,60(%edi)
+	#   bytes = bytes_backup
+	movl	76(%esp),%ebx
+	#   in8 = j8
+	movl	196(%esp),%eax
+	#   in9 = j9
+	movl	200(%esp),%ecx
+	#   in8 += 1
+	add	$1,%eax
+	#   in9 += 0 + carry
+	adc	$0,%ecx
+	#   j8 = in8
+	movl	%eax,196(%esp)
+	#   j9 = in9
+	movl	%ecx,200(%esp)
+	#   bytes - 64
+	cmp	$64,%ebx
+	#   goto bytesatleast65 if unsigned>
+	ja	._bytesatleast65
+	#     goto bytesatleast64 if unsigned>=
+	jae	._bytesatleast64
+	#       m = out
+	mov	%edi,%esi
+	#       out = ctarget
+	movl	228(%esp),%edi
+	#       i = bytes
+	mov	%ebx,%ecx
+	#       while (i) { *out++ = *m++; --i }
+	rep	movsb
+._bytesatleast64:
+	#     x = x_backup
+	movl	64(%esp),%eax
+	#     in8 = j8
+	movl	196(%esp),%ecx
+	#     in9 = j9
+	movl	200(%esp),%edx
+	#     *(uint32 *) (x + 32) = in8
+	movl	%ecx,32(%eax)
+	#     *(uint32 *) (x + 36) = in9
+	movl	%edx,36(%eax)
+._done:
+	#     eax = eax_stack
+	movl	80(%esp),%eax
+	#     ebx = ebx_stack
+	movl	84(%esp),%ebx
+	#     esi = esi_stack
+	movl	88(%esp),%esi
+	#     edi = edi_stack
+	movl	92(%esp),%edi
+	#     ebp = ebp_stack
+	movl	96(%esp),%ebp
+	#     leave
+	add	%eax,%esp
+	ret
+._bytesatleast65:
+	#   bytes -= 64
+	sub	$64,%ebx
+	#   out += 64
+	add	$64,%edi
+	#   m += 64
+	add	$64,%esi
+	# goto bytesatleast1
+	jmp	._bytesatleast1
+# enter ECRYPT_keysetup
+.text
+.p2align 5
+.globl ECRYPT_keysetup
+ECRYPT_keysetup:
+	mov	%esp,%eax
+	and	$31,%eax
+	add	$256,%eax
+	sub	%eax,%esp
+	#   eax_stack = eax
+	movl	%eax,64(%esp)
+	#   ebx_stack = ebx
+	movl	%ebx,68(%esp)
+	#   esi_stack = esi
+	movl	%esi,72(%esp)
+	#   edi_stack = edi
+	movl	%edi,76(%esp)
+	#   ebp_stack = ebp
+	movl	%ebp,80(%esp)
+	#   k = arg2
+	movl	8(%esp,%eax),%ecx
+	#   kbits = arg3
+	movl	12(%esp,%eax),%edx
+	#   x = arg1
+	movl	4(%esp,%eax),%eax
+	#   in1 = *(uint32 *) (k + 0)
+	movl	0(%ecx),%ebx
+	#   in2 = *(uint32 *) (k + 4)
+	movl	4(%ecx),%esi
+	#   in3 = *(uint32 *) (k + 8)
+	movl	8(%ecx),%edi
+	#   in4 = *(uint32 *) (k + 12)
+	movl	12(%ecx),%ebp
+	#   *(uint32 *) (x + 4) = in1
+	movl	%ebx,4(%eax)
+	#   *(uint32 *) (x + 8) = in2
+	movl	%esi,8(%eax)
+	#   *(uint32 *) (x + 12) = in3
+	movl	%edi,12(%eax)
+	#   *(uint32 *) (x + 16) = in4
+	movl	%ebp,16(%eax)
+	#   kbits - 256
+	cmp	$256,%edx
+	#   goto kbits128 if unsigned<
+	jb	._kbits128
+._kbits256:
+	#     in11 = *(uint32 *) (k + 16)
+	movl	16(%ecx),%edx
+	#     in12 = *(uint32 *) (k + 20)
+	movl	20(%ecx),%ebx
+	#     in13 = *(uint32 *) (k + 24)
+	movl	24(%ecx),%esi
+	#     in14 = *(uint32 *) (k + 28)
+	movl	28(%ecx),%ecx
+	#     *(uint32 *) (x + 44) = in11
+	movl	%edx,44(%eax)
+	#     *(uint32 *) (x + 48) = in12
+	movl	%ebx,48(%eax)
+	#     *(uint32 *) (x + 52) = in13
+	movl	%esi,52(%eax)
+	#     *(uint32 *) (x + 56) = in14
+	movl	%ecx,56(%eax)
+	#     in0 = 1634760805
+	mov	$1634760805,%ecx
+	#     in5 = 857760878
+	mov	$857760878,%edx
+	#     in10 = 2036477234
+	mov	$2036477234,%ebx
+	#     in15 = 1797285236
+	mov	$1797285236,%esi
+	#     *(uint32 *) (x + 0) = in0
+	movl	%ecx,0(%eax)
+	#     *(uint32 *) (x + 20) = in5
+	movl	%edx,20(%eax)
+	#     *(uint32 *) (x + 40) = in10
+	movl	%ebx,40(%eax)
+	#     *(uint32 *) (x + 60) = in15
+	movl	%esi,60(%eax)
+	#   goto keysetupdone
+	jmp	._keysetupdone
+._kbits128:
+	#     in11 = *(uint32 *) (k + 0)
+	movl	0(%ecx),%edx
+	#     in12 = *(uint32 *) (k + 4)
+	movl	4(%ecx),%ebx
+	#     in13 = *(uint32 *) (k + 8)
+	movl	8(%ecx),%esi
+	#     in14 = *(uint32 *) (k + 12)
+	movl	12(%ecx),%ecx
+	#     *(uint32 *) (x + 44) = in11
+	movl	%edx,44(%eax)
+	#     *(uint32 *) (x + 48) = in12
+	movl	%ebx,48(%eax)
+	#     *(uint32 *) (x + 52) = in13
+	movl	%esi,52(%eax)
+	#     *(uint32 *) (x + 56) = in14
+	movl	%ecx,56(%eax)
+	#     in0 = 1634760805
+	mov	$1634760805,%ecx
+	#     in5 = 824206446
+	mov	$824206446,%edx
+	#     in10 = 2036477238
+	mov	$2036477238,%ebx
+	#     in15 = 1797285236
+	mov	$1797285236,%esi
+	#     *(uint32 *) (x + 0) = in0
+	movl	%ecx,0(%eax)
+	#     *(uint32 *) (x + 20) = in5
+	movl	%edx,20(%eax)
+	#     *(uint32 *) (x + 40) = in10
+	movl	%ebx,40(%eax)
+	#     *(uint32 *) (x + 60) = in15
+	movl	%esi,60(%eax)
+._keysetupdone:
+	#   eax = eax_stack
+	movl	64(%esp),%eax
+	#   ebx = ebx_stack
+	movl	68(%esp),%ebx
+	#   esi = esi_stack
+	movl	72(%esp),%esi
+	#   edi = edi_stack
+	movl	76(%esp),%edi
+	#   ebp = ebp_stack
+	movl	80(%esp),%ebp
+	# leave
+	add	%eax,%esp
+	ret
+# enter ECRYPT_ivsetup
+.text
+.p2align 5
+.globl ECRYPT_ivsetup
+ECRYPT_ivsetup:
+	mov	%esp,%eax
+	and	$31,%eax
+	add	$256,%eax
+	sub	%eax,%esp
+	#   eax_stack = eax
+	movl	%eax,64(%esp)
+	#   ebx_stack = ebx
+	movl	%ebx,68(%esp)
+	#   esi_stack = esi
+	movl	%esi,72(%esp)
+	#   edi_stack = edi
+	movl	%edi,76(%esp)
+	#   ebp_stack = ebp
+	movl	%ebp,80(%esp)
+	#   iv = arg2
+	movl	8(%esp,%eax),%ecx
+	#   x = arg1
+	movl	4(%esp,%eax),%eax
+	#   in6 = *(uint32 *) (iv + 0)
+	movl	0(%ecx),%edx
+	#   in7 = *(uint32 *) (iv + 4)
+	movl	4(%ecx),%ecx
+	#   in8 = 0
+	mov	$0,%ebx
+	#   in9 = 0
+	mov	$0,%esi
+	#   *(uint32 *) (x + 24) = in6
+	movl	%edx,24(%eax)
+	#   *(uint32 *) (x + 28) = in7
+	movl	%ecx,28(%eax)
+	#   *(uint32 *) (x + 32) = in8
+	movl	%ebx,32(%eax)
+	#   *(uint32 *) (x + 36) = in9
+	movl	%esi,36(%eax)
+	#   eax = eax_stack
+	movl	64(%esp),%eax
+	#   ebx = ebx_stack
+	movl	68(%esp),%ebx
+	#   esi = esi_stack
+	movl	72(%esp),%esi
+	#   edi = edi_stack
+	movl	76(%esp),%edi
+	#   ebp = ebp_stack
+	movl	80(%esp),%ebp
+	# leave
+	add	%eax,%esp
+	ret

+ 920 - 0
arch/x86/crypto/salsa20-x86_64-asm_64.S

@@ -0,0 +1,920 @@
+# enter ECRYPT_encrypt_bytes
+.text
+.p2align 5
+.globl ECRYPT_encrypt_bytes
+ECRYPT_encrypt_bytes:
+	mov	%rsp,%r11
+	and	$31,%r11
+	add	$256,%r11
+	sub	%r11,%rsp
+	# x = arg1
+	mov	%rdi,%r8
+	# m = arg2
+	mov	%rsi,%rsi
+	# out = arg3
+	mov	%rdx,%rdi
+	# bytes = arg4
+	mov	%rcx,%rdx
+	#               unsigned>? bytes - 0
+	cmp	$0,%rdx
+	# comment:fp stack unchanged by jump
+	# goto done if !unsigned>
+	jbe	._done
+	# comment:fp stack unchanged by fallthrough
+# start:
+._start:
+	# r11_stack = r11
+	movq	%r11,0(%rsp)
+	# r12_stack = r12
+	movq	%r12,8(%rsp)
+	# r13_stack = r13
+	movq	%r13,16(%rsp)
+	# r14_stack = r14
+	movq	%r14,24(%rsp)
+	# r15_stack = r15
+	movq	%r15,32(%rsp)
+	# rbx_stack = rbx
+	movq	%rbx,40(%rsp)
+	# rbp_stack = rbp
+	movq	%rbp,48(%rsp)
+	# in0 = *(uint64 *) (x + 0)
+	movq	0(%r8),%rcx
+	# in2 = *(uint64 *) (x + 8)
+	movq	8(%r8),%r9
+	# in4 = *(uint64 *) (x + 16)
+	movq	16(%r8),%rax
+	# in6 = *(uint64 *) (x + 24)
+	movq	24(%r8),%r10
+	# in8 = *(uint64 *) (x + 32)
+	movq	32(%r8),%r11
+	# in10 = *(uint64 *) (x + 40)
+	movq	40(%r8),%r12
+	# in12 = *(uint64 *) (x + 48)
+	movq	48(%r8),%r13
+	# in14 = *(uint64 *) (x + 56)
+	movq	56(%r8),%r14
+	# j0 = in0
+	movq	%rcx,56(%rsp)
+	# j2 = in2
+	movq	%r9,64(%rsp)
+	# j4 = in4
+	movq	%rax,72(%rsp)
+	# j6 = in6
+	movq	%r10,80(%rsp)
+	# j8 = in8
+	movq	%r11,88(%rsp)
+	# j10 = in10
+	movq	%r12,96(%rsp)
+	# j12 = in12
+	movq	%r13,104(%rsp)
+	# j14 = in14
+	movq	%r14,112(%rsp)
+	# x_backup = x
+	movq	%r8,120(%rsp)
+# bytesatleast1:
+._bytesatleast1:
+	#                   unsigned<? bytes - 64
+	cmp	$64,%rdx
+	# comment:fp stack unchanged by jump
+	#   goto nocopy if !unsigned<
+	jae	._nocopy
+	#     ctarget = out
+	movq	%rdi,128(%rsp)
+	#     out = &tmp
+	leaq	192(%rsp),%rdi
+	#     i = bytes
+	mov	%rdx,%rcx
+	#     while (i) { *out++ = *m++; --i }
+	rep	movsb
+	#     out = &tmp
+	leaq	192(%rsp),%rdi
+	#     m = &tmp
+	leaq	192(%rsp),%rsi
+	# comment:fp stack unchanged by fallthrough
+#   nocopy:
+._nocopy:
+	#   out_backup = out
+	movq	%rdi,136(%rsp)
+	#   m_backup = m
+	movq	%rsi,144(%rsp)
+	#   bytes_backup = bytes
+	movq	%rdx,152(%rsp)
+	#   x1 = j0
+	movq	56(%rsp),%rdi
+	#   x0 = x1
+	mov	%rdi,%rdx
+	#   (uint64) x1 >>= 32
+	shr	$32,%rdi
+	#   		x3 = j2
+	movq	64(%rsp),%rsi
+	#   		x2 = x3
+	mov	%rsi,%rcx
+	#   		(uint64) x3 >>= 32
+	shr	$32,%rsi
+	#   x5 = j4
+	movq	72(%rsp),%r8
+	#   x4 = x5
+	mov	%r8,%r9
+	#   (uint64) x5 >>= 32
+	shr	$32,%r8
+	#   x5_stack = x5
+	movq	%r8,160(%rsp)
+	#   		x7 = j6
+	movq	80(%rsp),%r8
+	#   		x6 = x7
+	mov	%r8,%rax
+	#   		(uint64) x7 >>= 32
+	shr	$32,%r8
+	#   x9 = j8
+	movq	88(%rsp),%r10
+	#   x8 = x9
+	mov	%r10,%r11
+	#   (uint64) x9 >>= 32
+	shr	$32,%r10
+	#   		x11 = j10
+	movq	96(%rsp),%r12
+	#   		x10 = x11
+	mov	%r12,%r13
+	#   		x10_stack = x10
+	movq	%r13,168(%rsp)
+	#   		(uint64) x11 >>= 32
+	shr	$32,%r12
+	#   x13 = j12
+	movq	104(%rsp),%r13
+	#   x12 = x13
+	mov	%r13,%r14
+	#   (uint64) x13 >>= 32
+	shr	$32,%r13
+	#   		x15 = j14
+	movq	112(%rsp),%r15
+	#   		x14 = x15
+	mov	%r15,%rbx
+	#   		(uint64) x15 >>= 32
+	shr	$32,%r15
+	#   		x15_stack = x15
+	movq	%r15,176(%rsp)
+	#   i = 20
+	mov	$20,%r15
+#   mainloop:
+._mainloop:
+	#   i_backup = i
+	movq	%r15,184(%rsp)
+	# 		x5 = x5_stack
+	movq	160(%rsp),%r15
+	# a = x12 + x0
+	lea	(%r14,%rdx),%rbp
+	# (uint32) a <<<= 7
+	rol	$7,%ebp
+	# x4 ^= a
+	xor	%rbp,%r9
+	# 		b = x1 + x5
+	lea	(%rdi,%r15),%rbp
+	# 		(uint32) b <<<= 7
+	rol	$7,%ebp
+	# 		x9 ^= b
+	xor	%rbp,%r10
+	# a = x0 + x4
+	lea	(%rdx,%r9),%rbp
+	# (uint32) a <<<= 9
+	rol	$9,%ebp
+	# x8 ^= a
+	xor	%rbp,%r11
+	# 		b = x5 + x9
+	lea	(%r15,%r10),%rbp
+	# 		(uint32) b <<<= 9
+	rol	$9,%ebp
+	# 		x13 ^= b
+	xor	%rbp,%r13
+	# a = x4 + x8
+	lea	(%r9,%r11),%rbp
+	# (uint32) a <<<= 13
+	rol	$13,%ebp
+	# x12 ^= a
+	xor	%rbp,%r14
+	# 		b = x9 + x13
+	lea	(%r10,%r13),%rbp
+	# 		(uint32) b <<<= 13
+	rol	$13,%ebp
+	# 		x1 ^= b
+	xor	%rbp,%rdi
+	# a = x8 + x12
+	lea	(%r11,%r14),%rbp
+	# (uint32) a <<<= 18
+	rol	$18,%ebp
+	# x0 ^= a
+	xor	%rbp,%rdx
+	# 		b = x13 + x1
+	lea	(%r13,%rdi),%rbp
+	# 		(uint32) b <<<= 18
+	rol	$18,%ebp
+	# 		x5 ^= b
+	xor	%rbp,%r15
+	# 				x10 = x10_stack
+	movq	168(%rsp),%rbp
+	# 		x5_stack = x5
+	movq	%r15,160(%rsp)
+	# 				c = x6 + x10
+	lea	(%rax,%rbp),%r15
+	# 				(uint32) c <<<= 7
+	rol	$7,%r15d
+	# 				x14 ^= c
+	xor	%r15,%rbx
+	# 				c = x10 + x14
+	lea	(%rbp,%rbx),%r15
+	# 				(uint32) c <<<= 9
+	rol	$9,%r15d
+	# 				x2 ^= c
+	xor	%r15,%rcx
+	# 				c = x14 + x2
+	lea	(%rbx,%rcx),%r15
+	# 				(uint32) c <<<= 13
+	rol	$13,%r15d
+	# 				x6 ^= c
+	xor	%r15,%rax
+	# 				c = x2 + x6
+	lea	(%rcx,%rax),%r15
+	# 				(uint32) c <<<= 18
+	rol	$18,%r15d
+	# 				x10 ^= c
+	xor	%r15,%rbp
+	# 						x15 = x15_stack
+	movq	176(%rsp),%r15
+	# 				x10_stack = x10
+	movq	%rbp,168(%rsp)
+	# 						d = x11 + x15
+	lea	(%r12,%r15),%rbp
+	# 						(uint32) d <<<= 7
+	rol	$7,%ebp
+	# 						x3 ^= d
+	xor	%rbp,%rsi
+	# 						d = x15 + x3
+	lea	(%r15,%rsi),%rbp
+	# 						(uint32) d <<<= 9
+	rol	$9,%ebp
+	# 						x7 ^= d
+	xor	%rbp,%r8
+	# 						d = x3 + x7
+	lea	(%rsi,%r8),%rbp
+	# 						(uint32) d <<<= 13
+	rol	$13,%ebp
+	# 						x11 ^= d
+	xor	%rbp,%r12
+	# 						d = x7 + x11
+	lea	(%r8,%r12),%rbp
+	# 						(uint32) d <<<= 18
+	rol	$18,%ebp
+	# 						x15 ^= d
+	xor	%rbp,%r15
+	# 						x15_stack = x15
+	movq	%r15,176(%rsp)
+	# 		x5 = x5_stack
+	movq	160(%rsp),%r15
+	# a = x3 + x0
+	lea	(%rsi,%rdx),%rbp
+	# (uint32) a <<<= 7
+	rol	$7,%ebp
+	# x1 ^= a
+	xor	%rbp,%rdi
+	# 		b = x4 + x5
+	lea	(%r9,%r15),%rbp
+	# 		(uint32) b <<<= 7
+	rol	$7,%ebp
+	# 		x6 ^= b
+	xor	%rbp,%rax
+	# a = x0 + x1
+	lea	(%rdx,%rdi),%rbp
+	# (uint32) a <<<= 9
+	rol	$9,%ebp
+	# x2 ^= a
+	xor	%rbp,%rcx
+	# 		b = x5 + x6
+	lea	(%r15,%rax),%rbp
+	# 		(uint32) b <<<= 9
+	rol	$9,%ebp
+	# 		x7 ^= b
+	xor	%rbp,%r8
+	# a = x1 + x2
+	lea	(%rdi,%rcx),%rbp
+	# (uint32) a <<<= 13
+	rol	$13,%ebp
+	# x3 ^= a
+	xor	%rbp,%rsi
+	# 		b = x6 + x7
+	lea	(%rax,%r8),%rbp
+	# 		(uint32) b <<<= 13
+	rol	$13,%ebp
+	# 		x4 ^= b
+	xor	%rbp,%r9
+	# a = x2 + x3
+	lea	(%rcx,%rsi),%rbp
+	# (uint32) a <<<= 18
+	rol	$18,%ebp
+	# x0 ^= a
+	xor	%rbp,%rdx
+	# 		b = x7 + x4
+	lea	(%r8,%r9),%rbp
+	# 		(uint32) b <<<= 18
+	rol	$18,%ebp
+	# 		x5 ^= b
+	xor	%rbp,%r15
+	# 				x10 = x10_stack
+	movq	168(%rsp),%rbp
+	# 		x5_stack = x5
+	movq	%r15,160(%rsp)
+	# 				c = x9 + x10
+	lea	(%r10,%rbp),%r15
+	# 				(uint32) c <<<= 7
+	rol	$7,%r15d
+	# 				x11 ^= c
+	xor	%r15,%r12
+	# 				c = x10 + x11
+	lea	(%rbp,%r12),%r15
+	# 				(uint32) c <<<= 9
+	rol	$9,%r15d
+	# 				x8 ^= c
+	xor	%r15,%r11
+	# 				c = x11 + x8
+	lea	(%r12,%r11),%r15
+	# 				(uint32) c <<<= 13
+	rol	$13,%r15d
+	# 				x9 ^= c
+	xor	%r15,%r10
+	# 				c = x8 + x9
+	lea	(%r11,%r10),%r15
+	# 				(uint32) c <<<= 18
+	rol	$18,%r15d
+	# 				x10 ^= c
+	xor	%r15,%rbp
+	# 						x15 = x15_stack
+	movq	176(%rsp),%r15
+	# 				x10_stack = x10
+	movq	%rbp,168(%rsp)
+	# 						d = x14 + x15
+	lea	(%rbx,%r15),%rbp
+	# 						(uint32) d <<<= 7
+	rol	$7,%ebp
+	# 						x12 ^= d
+	xor	%rbp,%r14
+	# 						d = x15 + x12
+	lea	(%r15,%r14),%rbp
+	# 						(uint32) d <<<= 9
+	rol	$9,%ebp
+	# 						x13 ^= d
+	xor	%rbp,%r13
+	# 						d = x12 + x13
+	lea	(%r14,%r13),%rbp
+	# 						(uint32) d <<<= 13
+	rol	$13,%ebp
+	# 						x14 ^= d
+	xor	%rbp,%rbx
+	# 						d = x13 + x14
+	lea	(%r13,%rbx),%rbp
+	# 						(uint32) d <<<= 18
+	rol	$18,%ebp
+	# 						x15 ^= d
+	xor	%rbp,%r15
+	# 						x15_stack = x15
+	movq	%r15,176(%rsp)
+	# 		x5 = x5_stack
+	movq	160(%rsp),%r15
+	# a = x12 + x0
+	lea	(%r14,%rdx),%rbp
+	# (uint32) a <<<= 7
+	rol	$7,%ebp
+	# x4 ^= a
+	xor	%rbp,%r9
+	# 		b = x1 + x5
+	lea	(%rdi,%r15),%rbp
+	# 		(uint32) b <<<= 7
+	rol	$7,%ebp
+	# 		x9 ^= b
+	xor	%rbp,%r10
+	# a = x0 + x4
+	lea	(%rdx,%r9),%rbp
+	# (uint32) a <<<= 9
+	rol	$9,%ebp
+	# x8 ^= a
+	xor	%rbp,%r11
+	# 		b = x5 + x9
+	lea	(%r15,%r10),%rbp
+	# 		(uint32) b <<<= 9
+	rol	$9,%ebp
+	# 		x13 ^= b
+	xor	%rbp,%r13
+	# a = x4 + x8
+	lea	(%r9,%r11),%rbp
+	# (uint32) a <<<= 13
+	rol	$13,%ebp
+	# x12 ^= a
+	xor	%rbp,%r14
+	# 		b = x9 + x13
+	lea	(%r10,%r13),%rbp
+	# 		(uint32) b <<<= 13
+	rol	$13,%ebp
+	# 		x1 ^= b
+	xor	%rbp,%rdi
+	# a = x8 + x12
+	lea	(%r11,%r14),%rbp
+	# (uint32) a <<<= 18
+	rol	$18,%ebp
+	# x0 ^= a
+	xor	%rbp,%rdx
+	# 		b = x13 + x1
+	lea	(%r13,%rdi),%rbp
+	# 		(uint32) b <<<= 18
+	rol	$18,%ebp
+	# 		x5 ^= b
+	xor	%rbp,%r15
+	# 				x10 = x10_stack
+	movq	168(%rsp),%rbp
+	# 		x5_stack = x5
+	movq	%r15,160(%rsp)
+	# 				c = x6 + x10
+	lea	(%rax,%rbp),%r15
+	# 				(uint32) c <<<= 7
+	rol	$7,%r15d
+	# 				x14 ^= c
+	xor	%r15,%rbx
+	# 				c = x10 + x14
+	lea	(%rbp,%rbx),%r15
+	# 				(uint32) c <<<= 9
+	rol	$9,%r15d
+	# 				x2 ^= c
+	xor	%r15,%rcx
+	# 				c = x14 + x2
+	lea	(%rbx,%rcx),%r15
+	# 				(uint32) c <<<= 13
+	rol	$13,%r15d
+	# 				x6 ^= c
+	xor	%r15,%rax
+	# 				c = x2 + x6
+	lea	(%rcx,%rax),%r15
+	# 				(uint32) c <<<= 18
+	rol	$18,%r15d
+	# 				x10 ^= c
+	xor	%r15,%rbp
+	# 						x15 = x15_stack
+	movq	176(%rsp),%r15
+	# 				x10_stack = x10
+	movq	%rbp,168(%rsp)
+	# 						d = x11 + x15
+	lea	(%r12,%r15),%rbp
+	# 						(uint32) d <<<= 7
+	rol	$7,%ebp
+	# 						x3 ^= d
+	xor	%rbp,%rsi
+	# 						d = x15 + x3
+	lea	(%r15,%rsi),%rbp
+	# 						(uint32) d <<<= 9
+	rol	$9,%ebp
+	# 						x7 ^= d
+	xor	%rbp,%r8
+	# 						d = x3 + x7
+	lea	(%rsi,%r8),%rbp
+	# 						(uint32) d <<<= 13
+	rol	$13,%ebp
+	# 						x11 ^= d
+	xor	%rbp,%r12
+	# 						d = x7 + x11
+	lea	(%r8,%r12),%rbp
+	# 						(uint32) d <<<= 18
+	rol	$18,%ebp
+	# 						x15 ^= d
+	xor	%rbp,%r15
+	# 						x15_stack = x15
+	movq	%r15,176(%rsp)
+	# 		x5 = x5_stack
+	movq	160(%rsp),%r15
+	# a = x3 + x0
+	lea	(%rsi,%rdx),%rbp
+	# (uint32) a <<<= 7
+	rol	$7,%ebp
+	# x1 ^= a
+	xor	%rbp,%rdi
+	# 		b = x4 + x5
+	lea	(%r9,%r15),%rbp
+	# 		(uint32) b <<<= 7
+	rol	$7,%ebp
+	# 		x6 ^= b
+	xor	%rbp,%rax
+	# a = x0 + x1
+	lea	(%rdx,%rdi),%rbp
+	# (uint32) a <<<= 9
+	rol	$9,%ebp
+	# x2 ^= a
+	xor	%rbp,%rcx
+	# 		b = x5 + x6
+	lea	(%r15,%rax),%rbp
+	# 		(uint32) b <<<= 9
+	rol	$9,%ebp
+	# 		x7 ^= b
+	xor	%rbp,%r8
+	# a = x1 + x2
+	lea	(%rdi,%rcx),%rbp
+	# (uint32) a <<<= 13
+	rol	$13,%ebp
+	# x3 ^= a
+	xor	%rbp,%rsi
+	# 		b = x6 + x7
+	lea	(%rax,%r8),%rbp
+	# 		(uint32) b <<<= 13
+	rol	$13,%ebp
+	# 		x4 ^= b
+	xor	%rbp,%r9
+	# a = x2 + x3
+	lea	(%rcx,%rsi),%rbp
+	# (uint32) a <<<= 18
+	rol	$18,%ebp
+	# x0 ^= a
+	xor	%rbp,%rdx
+	# 		b = x7 + x4
+	lea	(%r8,%r9),%rbp
+	# 		(uint32) b <<<= 18
+	rol	$18,%ebp
+	# 		x5 ^= b
+	xor	%rbp,%r15
+	# 				x10 = x10_stack
+	movq	168(%rsp),%rbp
+	# 		x5_stack = x5
+	movq	%r15,160(%rsp)
+	# 				c = x9 + x10
+	lea	(%r10,%rbp),%r15
+	# 				(uint32) c <<<= 7
+	rol	$7,%r15d
+	# 				x11 ^= c
+	xor	%r15,%r12
+	# 				c = x10 + x11
+	lea	(%rbp,%r12),%r15
+	# 				(uint32) c <<<= 9
+	rol	$9,%r15d
+	# 				x8 ^= c
+	xor	%r15,%r11
+	# 				c = x11 + x8
+	lea	(%r12,%r11),%r15
+	# 				(uint32) c <<<= 13
+	rol	$13,%r15d
+	# 				x9 ^= c
+	xor	%r15,%r10
+	# 				c = x8 + x9
+	lea	(%r11,%r10),%r15
+	# 				(uint32) c <<<= 18
+	rol	$18,%r15d
+	# 				x10 ^= c
+	xor	%r15,%rbp
+	# 						x15 = x15_stack
+	movq	176(%rsp),%r15
+	# 				x10_stack = x10
+	movq	%rbp,168(%rsp)
+	# 						d = x14 + x15
+	lea	(%rbx,%r15),%rbp
+	# 						(uint32) d <<<= 7
+	rol	$7,%ebp
+	# 						x12 ^= d
+	xor	%rbp,%r14
+	# 						d = x15 + x12
+	lea	(%r15,%r14),%rbp
+	# 						(uint32) d <<<= 9
+	rol	$9,%ebp
+	# 						x13 ^= d
+	xor	%rbp,%r13
+	# 						d = x12 + x13
+	lea	(%r14,%r13),%rbp
+	# 						(uint32) d <<<= 13
+	rol	$13,%ebp
+	# 						x14 ^= d
+	xor	%rbp,%rbx
+	# 						d = x13 + x14
+	lea	(%r13,%rbx),%rbp
+	# 						(uint32) d <<<= 18
+	rol	$18,%ebp
+	# 						x15 ^= d
+	xor	%rbp,%r15
+	# 						x15_stack = x15
+	movq	%r15,176(%rsp)
+	#   i = i_backup
+	movq	184(%rsp),%r15
+	#                  unsigned>? i -= 4
+	sub	$4,%r15
+	# comment:fp stack unchanged by jump
+	# goto mainloop if unsigned>
+	ja	._mainloop
+	#   (uint32) x2 += j2
+	addl	64(%rsp),%ecx
+	#   x3 <<= 32
+	shl	$32,%rsi
+	#   x3 += j2
+	addq	64(%rsp),%rsi
+	#   (uint64) x3 >>= 32
+	shr	$32,%rsi
+	#   x3 <<= 32
+	shl	$32,%rsi
+	#   x2 += x3
+	add	%rsi,%rcx
+	#   (uint32) x6 += j6
+	addl	80(%rsp),%eax
+	#   x7 <<= 32
+	shl	$32,%r8
+	#   x7 += j6
+	addq	80(%rsp),%r8
+	#   (uint64) x7 >>= 32
+	shr	$32,%r8
+	#   x7 <<= 32
+	shl	$32,%r8
+	#   x6 += x7
+	add	%r8,%rax
+	#   (uint32) x8 += j8
+	addl	88(%rsp),%r11d
+	#   x9 <<= 32
+	shl	$32,%r10
+	#   x9 += j8
+	addq	88(%rsp),%r10
+	#   (uint64) x9 >>= 32
+	shr	$32,%r10
+	#   x9 <<= 32
+	shl	$32,%r10
+	#   x8 += x9
+	add	%r10,%r11
+	#   (uint32) x12 += j12
+	addl	104(%rsp),%r14d
+	#   x13 <<= 32
+	shl	$32,%r13
+	#   x13 += j12
+	addq	104(%rsp),%r13
+	#   (uint64) x13 >>= 32
+	shr	$32,%r13
+	#   x13 <<= 32
+	shl	$32,%r13
+	#   x12 += x13
+	add	%r13,%r14
+	#   (uint32) x0 += j0
+	addl	56(%rsp),%edx
+	#   x1 <<= 32
+	shl	$32,%rdi
+	#   x1 += j0
+	addq	56(%rsp),%rdi
+	#   (uint64) x1 >>= 32
+	shr	$32,%rdi
+	#   x1 <<= 32
+	shl	$32,%rdi
+	#   x0 += x1
+	add	%rdi,%rdx
+	#   x5 = x5_stack
+	movq	160(%rsp),%rdi
+	#   (uint32) x4 += j4
+	addl	72(%rsp),%r9d
+	#   x5 <<= 32
+	shl	$32,%rdi
+	#   x5 += j4
+	addq	72(%rsp),%rdi
+	#   (uint64) x5 >>= 32
+	shr	$32,%rdi
+	#   x5 <<= 32
+	shl	$32,%rdi
+	#   x4 += x5
+	add	%rdi,%r9
+	#   x10 = x10_stack
+	movq	168(%rsp),%r8
+	#   (uint32) x10 += j10
+	addl	96(%rsp),%r8d
+	#   x11 <<= 32
+	shl	$32,%r12
+	#   x11 += j10
+	addq	96(%rsp),%r12
+	#   (uint64) x11 >>= 32
+	shr	$32,%r12
+	#   x11 <<= 32
+	shl	$32,%r12
+	#   x10 += x11
+	add	%r12,%r8
+	#   x15 = x15_stack
+	movq	176(%rsp),%rdi
+	#   (uint32) x14 += j14
+	addl	112(%rsp),%ebx
+	#   x15 <<= 32
+	shl	$32,%rdi
+	#   x15 += j14
+	addq	112(%rsp),%rdi
+	#   (uint64) x15 >>= 32
+	shr	$32,%rdi
+	#   x15 <<= 32
+	shl	$32,%rdi
+	#   x14 += x15
+	add	%rdi,%rbx
+	#   out = out_backup
+	movq	136(%rsp),%rdi
+	#   m = m_backup
+	movq	144(%rsp),%rsi
+	#   x0 ^= *(uint64 *) (m + 0)
+	xorq	0(%rsi),%rdx
+	#   *(uint64 *) (out + 0) = x0
+	movq	%rdx,0(%rdi)
+	#   x2 ^= *(uint64 *) (m + 8)
+	xorq	8(%rsi),%rcx
+	#   *(uint64 *) (out + 8) = x2
+	movq	%rcx,8(%rdi)
+	#   x4 ^= *(uint64 *) (m + 16)
+	xorq	16(%rsi),%r9
+	#   *(uint64 *) (out + 16) = x4
+	movq	%r9,16(%rdi)
+	#   x6 ^= *(uint64 *) (m + 24)
+	xorq	24(%rsi),%rax
+	#   *(uint64 *) (out + 24) = x6
+	movq	%rax,24(%rdi)
+	#   x8 ^= *(uint64 *) (m + 32)
+	xorq	32(%rsi),%r11
+	#   *(uint64 *) (out + 32) = x8
+	movq	%r11,32(%rdi)
+	#   x10 ^= *(uint64 *) (m + 40)
+	xorq	40(%rsi),%r8
+	#   *(uint64 *) (out + 40) = x10
+	movq	%r8,40(%rdi)
+	#   x12 ^= *(uint64 *) (m + 48)
+	xorq	48(%rsi),%r14
+	#   *(uint64 *) (out + 48) = x12
+	movq	%r14,48(%rdi)
+	#   x14 ^= *(uint64 *) (m + 56)
+	xorq	56(%rsi),%rbx
+	#   *(uint64 *) (out + 56) = x14
+	movq	%rbx,56(%rdi)
+	#   bytes = bytes_backup
+	movq	152(%rsp),%rdx
+	#   in8 = j8
+	movq	88(%rsp),%rcx
+	#   in8 += 1
+	add	$1,%rcx
+	#   j8 = in8
+	movq	%rcx,88(%rsp)
+	#                          unsigned>? unsigned<? bytes - 64
+	cmp	$64,%rdx
+	# comment:fp stack unchanged by jump
+	#   goto bytesatleast65 if unsigned>
+	ja	._bytesatleast65
+	# comment:fp stack unchanged by jump
+	#     goto bytesatleast64 if !unsigned<
+	jae	._bytesatleast64
+	#       m = out
+	mov	%rdi,%rsi
+	#       out = ctarget
+	movq	128(%rsp),%rdi
+	#       i = bytes
+	mov	%rdx,%rcx
+	#       while (i) { *out++ = *m++; --i }
+	rep	movsb
+	# comment:fp stack unchanged by fallthrough
+#     bytesatleast64:
+._bytesatleast64:
+	#     x = x_backup
+	movq	120(%rsp),%rdi
+	#     in8 = j8
+	movq	88(%rsp),%rsi
+	#     *(uint64 *) (x + 32) = in8
+	movq	%rsi,32(%rdi)
+	#     r11 = r11_stack
+	movq	0(%rsp),%r11
+	#     r12 = r12_stack
+	movq	8(%rsp),%r12
+	#     r13 = r13_stack
+	movq	16(%rsp),%r13
+	#     r14 = r14_stack
+	movq	24(%rsp),%r14
+	#     r15 = r15_stack
+	movq	32(%rsp),%r15
+	#     rbx = rbx_stack
+	movq	40(%rsp),%rbx
+	#     rbp = rbp_stack
+	movq	48(%rsp),%rbp
+	# comment:fp stack unchanged by fallthrough
+#     done:
+._done:
+	#     leave
+	add	%r11,%rsp
+	mov	%rdi,%rax
+	mov	%rsi,%rdx
+	ret
+#   bytesatleast65:
+._bytesatleast65:
+	#   bytes -= 64
+	sub	$64,%rdx
+	#   out += 64
+	add	$64,%rdi
+	#   m += 64
+	add	$64,%rsi
+	# comment:fp stack unchanged by jump
+	# goto bytesatleast1
+	jmp	._bytesatleast1
+# enter ECRYPT_keysetup
+.text
+.p2align 5
+.globl ECRYPT_keysetup
+ECRYPT_keysetup:
+	mov	%rsp,%r11
+	and	$31,%r11
+	add	$256,%r11
+	sub	%r11,%rsp
+	#   k = arg2
+	mov	%rsi,%rsi
+	#   kbits = arg3
+	mov	%rdx,%rdx
+	#   x = arg1
+	mov	%rdi,%rdi
+	#   in0 = *(uint64 *) (k + 0)
+	movq	0(%rsi),%r8
+	#   in2 = *(uint64 *) (k + 8)
+	movq	8(%rsi),%r9
+	#   *(uint64 *) (x + 4) = in0
+	movq	%r8,4(%rdi)
+	#   *(uint64 *) (x + 12) = in2
+	movq	%r9,12(%rdi)
+	#                    unsigned<? kbits - 256
+	cmp	$256,%rdx
+	# comment:fp stack unchanged by jump
+	#   goto kbits128 if unsigned<
+	jb	._kbits128
+#   kbits256:
+._kbits256:
+	#     in10 = *(uint64 *) (k + 16)
+	movq	16(%rsi),%rdx
+	#     in12 = *(uint64 *) (k + 24)
+	movq	24(%rsi),%rsi
+	#     *(uint64 *) (x + 44) = in10
+	movq	%rdx,44(%rdi)
+	#     *(uint64 *) (x + 52) = in12
+	movq	%rsi,52(%rdi)
+	#     in0 = 1634760805
+	mov	$1634760805,%rsi
+	#     in4 = 857760878
+	mov	$857760878,%rdx
+	#     in10 = 2036477234
+	mov	$2036477234,%rcx
+	#     in14 = 1797285236
+	mov	$1797285236,%r8
+	#     *(uint32 *) (x + 0) = in0
+	movl	%esi,0(%rdi)
+	#     *(uint32 *) (x + 20) = in4
+	movl	%edx,20(%rdi)
+	#     *(uint32 *) (x + 40) = in10
+	movl	%ecx,40(%rdi)
+	#     *(uint32 *) (x + 60) = in14
+	movl	%r8d,60(%rdi)
+	# comment:fp stack unchanged by jump
+	#   goto keysetupdone
+	jmp	._keysetupdone
+#   kbits128:
+._kbits128:
+	#     in10 = *(uint64 *) (k + 0)
+	movq	0(%rsi),%rdx
+	#     in12 = *(uint64 *) (k + 8)
+	movq	8(%rsi),%rsi
+	#     *(uint64 *) (x + 44) = in10
+	movq	%rdx,44(%rdi)
+	#     *(uint64 *) (x + 52) = in12
+	movq	%rsi,52(%rdi)
+	#     in0 = 1634760805
+	mov	$1634760805,%rsi
+	#     in4 = 824206446
+	mov	$824206446,%rdx
+	#     in10 = 2036477238
+	mov	$2036477238,%rcx
+	#     in14 = 1797285236
+	mov	$1797285236,%r8
+	#     *(uint32 *) (x + 0) = in0
+	movl	%esi,0(%rdi)
+	#     *(uint32 *) (x + 20) = in4
+	movl	%edx,20(%rdi)
+	#     *(uint32 *) (x + 40) = in10
+	movl	%ecx,40(%rdi)
+	#     *(uint32 *) (x + 60) = in14
+	movl	%r8d,60(%rdi)
+#   keysetupdone:
+._keysetupdone:
+	# leave
+	add	%r11,%rsp
+	mov	%rdi,%rax
+	mov	%rsi,%rdx
+	ret
+# enter ECRYPT_ivsetup
+.text
+.p2align 5
+.globl ECRYPT_ivsetup
+ECRYPT_ivsetup:
+	mov	%rsp,%r11
+	and	$31,%r11
+	add	$256,%r11
+	sub	%r11,%rsp
+	#   iv = arg2
+	mov	%rsi,%rsi
+	#   x = arg1
+	mov	%rdi,%rdi
+	#   in6 = *(uint64 *) (iv + 0)
+	movq	0(%rsi),%rsi
+	#   in8 = 0
+	mov	$0,%r8
+	#   *(uint64 *) (x + 24) = in6
+	movq	%rsi,24(%rdi)
+	#   *(uint64 *) (x + 32) = in8
+	movq	%r8,32(%rdi)
+	# leave
+	add	%r11,%rsp
+	mov	%rdi,%rax
+	mov	%rsi,%rdx
+	ret

+ 129 - 0
arch/x86/crypto/salsa20_glue.c

@@ -0,0 +1,129 @@
+/*
+ * Glue code for optimized assembly version of  Salsa20.
+ *
+ * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com>
+ *
+ * The assembly codes are public domain assembly codes written by Daniel. J.
+ * Bernstein <djb@cr.yp.to>. The codes are modified to include indentation
+ * and to remove extraneous comments and functions that are not needed.
+ * - i586 version, renamed as salsa20-i586-asm_32.S
+ *   available from <http://cr.yp.to/snuffle/salsa20/x86-pm/salsa20.s>
+ * - x86-64 version, renamed as salsa20-x86_64-asm_64.S
+ *   available from <http://cr.yp.to/snuffle/salsa20/amd64-3/salsa20.s>
+ *
+ * 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 <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+
+#define SALSA20_IV_SIZE        8U
+#define SALSA20_MIN_KEY_SIZE  16U
+#define SALSA20_MAX_KEY_SIZE  32U
+
+// use the ECRYPT_* function names
+#define salsa20_keysetup        ECRYPT_keysetup
+#define salsa20_ivsetup         ECRYPT_ivsetup
+#define salsa20_encrypt_bytes   ECRYPT_encrypt_bytes
+
+struct salsa20_ctx
+{
+	u32 input[16];
+};
+
+asmlinkage void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k,
+				 u32 keysize, u32 ivsize);
+asmlinkage void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv);
+asmlinkage void salsa20_encrypt_bytes(struct salsa20_ctx *ctx,
+				      const u8 *src, u8 *dst, u32 bytes);
+
+static int setkey(struct crypto_tfm *tfm, const u8 *key,
+		  unsigned int keysize)
+{
+	struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm);
+	salsa20_keysetup(ctx, key, keysize*8, SALSA20_IV_SIZE*8);
+	return 0;
+}
+
+static int encrypt(struct blkcipher_desc *desc,
+		   struct scatterlist *dst, struct scatterlist *src,
+		   unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	struct crypto_blkcipher *tfm = desc->tfm;
+	struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm);
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt_block(desc, &walk, 64);
+
+	salsa20_ivsetup(ctx, walk.iv);
+
+	if (likely(walk.nbytes == nbytes))
+	{
+		salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
+				      walk.dst.virt.addr, nbytes);
+		return blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	while (walk.nbytes >= 64) {
+		salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
+				      walk.dst.virt.addr,
+				      walk.nbytes - (walk.nbytes % 64));
+		err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64);
+	}
+
+	if (walk.nbytes) {
+		salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
+				      walk.dst.virt.addr, walk.nbytes);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+static struct crypto_alg alg = {
+	.cra_name           =   "salsa20",
+	.cra_driver_name    =   "salsa20-asm",
+	.cra_priority       =   200,
+	.cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_type           =   &crypto_blkcipher_type,
+	.cra_blocksize      =   1,
+	.cra_ctxsize        =   sizeof(struct salsa20_ctx),
+	.cra_alignmask      =	3,
+	.cra_module         =   THIS_MODULE,
+	.cra_list           =   LIST_HEAD_INIT(alg.cra_list),
+	.cra_u              =   {
+		.blkcipher = {
+			.setkey         =   setkey,
+			.encrypt        =   encrypt,
+			.decrypt        =   encrypt,
+			.min_keysize    =   SALSA20_MIN_KEY_SIZE,
+			.max_keysize    =   SALSA20_MAX_KEY_SIZE,
+			.ivsize         =   SALSA20_IV_SIZE,
+		}
+	}
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm (optimized assembly version)");
+MODULE_ALIAS("salsa20");
+MODULE_ALIAS("salsa20-asm");

+ 0 - 97
arch/x86/crypto/twofish_64.c

@@ -1,97 +0,0 @@
-/*
- * Glue Code for optimized x86_64 assembler version of TWOFISH
- *
- * Originally Twofish for GPG
- * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
- * 256-bit key length added March 20, 1999
- * Some modifications to reduce the text size by Werner Koch, April, 1998
- * Ported to the kerneli patch by Marc Mutz <Marc@Mutz.com>
- * Ported to CryptoAPI by Colin Slater <hoho@tacomeat.net>
- *
- * The original author has disclaimed all copyright interest in this
- * code and thus put it in the public domain. The subsequent authors
- * have put this under the GNU General Public License.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
- * USA
- *
- * This code is a "clean room" implementation, written from the paper
- * _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
- * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
- * through http://www.counterpane.com/twofish.html
- *
- * For background information on multiplication in finite fields, used for
- * the matrix operations in the key schedule, see the book _Contemporary
- * Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
- * Third Edition.
- */
-
-#include <crypto/twofish.h>
-#include <linux/crypto.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
-
-static void twofish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	twofish_enc_blk(tfm, dst, src);
-}
-
-static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-	twofish_dec_blk(tfm, dst, src);
-}
-
-static struct crypto_alg alg = {
-	.cra_name		=	"twofish",
-	.cra_driver_name	=	"twofish-x86_64",
-	.cra_priority		=	200,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize		=	TF_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct twofish_ctx),
-	.cra_alignmask		=	3,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(alg.cra_list),
-	.cra_u			=	{
-		.cipher = {
-			.cia_min_keysize	=	TF_MIN_KEY_SIZE,
-			.cia_max_keysize	=	TF_MAX_KEY_SIZE,
-			.cia_setkey		=	twofish_setkey,
-			.cia_encrypt		=	twofish_encrypt,
-			.cia_decrypt		=	twofish_decrypt
-		}
-	}
-};
-
-static int __init init(void)
-{
-	return crypto_register_alg(&alg);
-}
-
-static void __exit fini(void)
-{
-	crypto_unregister_alg(&alg);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION ("Twofish Cipher Algorithm, x86_64 asm optimized");
-MODULE_ALIAS("twofish");

+ 4 - 4
arch/x86/crypto/twofish_32.c → arch/x86/crypto/twofish_glue.c

@@ -1,5 +1,5 @@
 /*
 /*
- *  Glue Code for optimized 586 assembler version of TWOFISH
+ * Glue Code for assembler optimized version of TWOFISH
  *
  *
  * Originally Twofish for GPG
  * Originally Twofish for GPG
  * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
  * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
@@ -44,7 +44,6 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/types.h>
 
 
-
 asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 asmlinkage void twofish_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 asmlinkage void twofish_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 
 
@@ -60,7 +59,7 @@ static void twofish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 
 
 static struct crypto_alg alg = {
 static struct crypto_alg alg = {
 	.cra_name		=	"twofish",
 	.cra_name		=	"twofish",
-	.cra_driver_name	=	"twofish-i586",
+	.cra_driver_name	=	"twofish-asm",
 	.cra_priority		=	200,
 	.cra_priority		=	200,
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	TF_BLOCK_SIZE,
 	.cra_blocksize		=	TF_BLOCK_SIZE,
@@ -93,5 +92,6 @@ module_init(init);
 module_exit(fini);
 module_exit(fini);
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION ("Twofish Cipher Algorithm, i586 asm optimized");
+MODULE_DESCRIPTION ("Twofish Cipher Algorithm, asm optimized");
 MODULE_ALIAS("twofish");
 MODULE_ALIAS("twofish");
+MODULE_ALIAS("twofish-asm");

+ 91 - 6
crypto/Kconfig

@@ -24,10 +24,6 @@ config CRYPTO_ALGAPI
 	help
 	help
 	  This option provides the API for cryptographic algorithms.
 	  This option provides the API for cryptographic algorithms.
 
 
-config CRYPTO_ABLKCIPHER
-	tristate
-	select CRYPTO_BLKCIPHER
-
 config CRYPTO_AEAD
 config CRYPTO_AEAD
 	tristate
 	tristate
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
@@ -36,6 +32,15 @@ config CRYPTO_BLKCIPHER
 	tristate
 	tristate
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
 
 
+config CRYPTO_SEQIV
+	tristate "Sequence Number IV Generator"
+	select CRYPTO_AEAD
+	select CRYPTO_BLKCIPHER
+	help
+	  This IV generator generates an IV based on a sequence number by
+	  xoring it with a salt.  This algorithm is mainly useful for CTR
+	  and similar modes.
+
 config CRYPTO_HASH
 config CRYPTO_HASH
 	tristate
 	tristate
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
@@ -91,7 +96,7 @@ config CRYPTO_SHA1
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
 
 config CRYPTO_SHA256
 config CRYPTO_SHA256
-	tristate "SHA256 digest algorithm"
+	tristate "SHA224 and SHA256 digest algorithm"
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
 	help
 	help
 	  SHA256 secure hash standard (DFIPS 180-2).
 	  SHA256 secure hash standard (DFIPS 180-2).
@@ -99,6 +104,9 @@ config CRYPTO_SHA256
 	  This version of SHA implements a 256 bit hash with 128 bits of
 	  This version of SHA implements a 256 bit hash with 128 bits of
 	  security against collision attacks.
 	  security against collision attacks.
 
 
+          This code also includes SHA-224, a 224 bit hash with 112 bits
+          of security against collision attacks.
+
 config CRYPTO_SHA512
 config CRYPTO_SHA512
 	tristate "SHA384 and SHA512 digest algorithms"
 	tristate "SHA384 and SHA512 digest algorithms"
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
@@ -195,9 +203,34 @@ config CRYPTO_XTS
 	  key size 256, 384 or 512 bits. This implementation currently
 	  key size 256, 384 or 512 bits. This implementation currently
 	  can't handle a sectorsize which is not a multiple of 16 bytes.
 	  can't handle a sectorsize which is not a multiple of 16 bytes.
 
 
+config CRYPTO_CTR
+	tristate "CTR support"
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_SEQIV
+	select CRYPTO_MANAGER
+	help
+	  CTR: Counter mode
+	  This block cipher algorithm is required for IPSec.
+
+config CRYPTO_GCM
+	tristate "GCM/GMAC support"
+	select CRYPTO_CTR
+	select CRYPTO_AEAD
+	select CRYPTO_GF128MUL
+	help
+	  Support for Galois/Counter Mode (GCM) and Galois Message
+	  Authentication Code (GMAC). Required for IPSec.
+
+config CRYPTO_CCM
+	tristate "CCM support"
+	select CRYPTO_CTR
+	select CRYPTO_AEAD
+	help
+	  Support for Counter with CBC MAC. Required for IPsec.
+
 config CRYPTO_CRYPTD
 config CRYPTO_CRYPTD
 	tristate "Software async crypto daemon"
 	tristate "Software async crypto daemon"
-	select CRYPTO_ABLKCIPHER
+	select CRYPTO_BLKCIPHER
 	select CRYPTO_MANAGER
 	select CRYPTO_MANAGER
 	help
 	help
 	  This is a generic software asynchronous crypto daemon that
 	  This is a generic software asynchronous crypto daemon that
@@ -320,6 +353,7 @@ config CRYPTO_AES_586
 	tristate "AES cipher algorithms (i586)"
 	tristate "AES cipher algorithms (i586)"
 	depends on (X86 || UML_X86) && !64BIT
 	depends on (X86 || UML_X86) && !64BIT
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
+	select CRYPTO_AES
 	help
 	help
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  algorithm.
 	  algorithm.
@@ -341,6 +375,7 @@ config CRYPTO_AES_X86_64
 	tristate "AES cipher algorithms (x86_64)"
 	tristate "AES cipher algorithms (x86_64)"
 	depends on (X86 || UML_X86) && 64BIT
 	depends on (X86 || UML_X86) && 64BIT
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
+	select CRYPTO_AES
 	help
 	help
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  AES cipher algorithms (FIPS-197). AES uses the Rijndael 
 	  algorithm.
 	  algorithm.
@@ -441,6 +476,46 @@ config CRYPTO_SEED
 	  See also:
 	  See also:
 	  <http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp>
 	  <http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp>
 
 
+config CRYPTO_SALSA20
+	tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select CRYPTO_BLKCIPHER
+	help
+	  Salsa20 stream cipher algorithm.
+
+	  Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT
+	  Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/>
+
+	  The Salsa20 stream cipher algorithm is designed by Daniel J.
+	  Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
+
+config CRYPTO_SALSA20_586
+	tristate "Salsa20 stream cipher algorithm (i586) (EXPERIMENTAL)"
+	depends on (X86 || UML_X86) && !64BIT
+	depends on EXPERIMENTAL
+	select CRYPTO_BLKCIPHER
+	help
+	  Salsa20 stream cipher algorithm.
+
+	  Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT
+	  Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/>
+
+	  The Salsa20 stream cipher algorithm is designed by Daniel J.
+	  Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
+
+config CRYPTO_SALSA20_X86_64
+	tristate "Salsa20 stream cipher algorithm (x86_64) (EXPERIMENTAL)"
+	depends on (X86 || UML_X86) && 64BIT
+	depends on EXPERIMENTAL
+	select CRYPTO_BLKCIPHER
+	help
+	  Salsa20 stream cipher algorithm.
+
+	  Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT
+	  Stream Cipher Project. See <http://www.ecrypt.eu.org/stream/>
+
+	  The Salsa20 stream cipher algorithm is designed by Daniel J.
+	  Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
 
 
 config CRYPTO_DEFLATE
 config CRYPTO_DEFLATE
 	tristate "Deflate compression algorithm"
 	tristate "Deflate compression algorithm"
@@ -491,6 +566,7 @@ config CRYPTO_TEST
 	tristate "Testing module"
 	tristate "Testing module"
 	depends on m
 	depends on m
 	select CRYPTO_ALGAPI
 	select CRYPTO_ALGAPI
+	select CRYPTO_AEAD
 	help
 	help
 	  Quick & dirty crypto test module.
 	  Quick & dirty crypto test module.
 
 
@@ -498,10 +574,19 @@ config CRYPTO_AUTHENC
 	tristate "Authenc support"
 	tristate "Authenc support"
 	select CRYPTO_AEAD
 	select CRYPTO_AEAD
 	select CRYPTO_MANAGER
 	select CRYPTO_MANAGER
+	select CRYPTO_HASH
 	help
 	help
 	  Authenc: Combined mode wrapper for IPsec.
 	  Authenc: Combined mode wrapper for IPsec.
 	  This is required for IPSec.
 	  This is required for IPSec.
 
 
+config CRYPTO_LZO
+	tristate "LZO compression algorithm"
+	select CRYPTO_ALGAPI
+	select LZO_COMPRESS
+	select LZO_DECOMPRESS
+	help
+	  This is the LZO algorithm.
+
 source "drivers/crypto/Kconfig"
 source "drivers/crypto/Kconfig"
 
 
 endif	# if CRYPTO
 endif	# if CRYPTO

+ 12 - 2
crypto/Makefile

@@ -8,9 +8,14 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o
 crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y)
 crypto_algapi-objs := algapi.o scatterwalk.o $(crypto_algapi-y)
 obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
 obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
 
 
-obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o
 obj-$(CONFIG_CRYPTO_AEAD) += aead.o
 obj-$(CONFIG_CRYPTO_AEAD) += aead.o
-obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
+
+crypto_blkcipher-objs := ablkcipher.o
+crypto_blkcipher-objs += blkcipher.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
+obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
 
 
 crypto_hash-objs := hash.o
 crypto_hash-objs := hash.o
 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
@@ -32,6 +37,9 @@ obj-$(CONFIG_CRYPTO_CBC) += cbc.o
 obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
 obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_XTS) += xts.o
 obj-$(CONFIG_CRYPTO_XTS) += xts.o
+obj-$(CONFIG_CRYPTO_CTR) += ctr.o
+obj-$(CONFIG_CRYPTO_GCM) += gcm.o
+obj-$(CONFIG_CRYPTO_CCM) += ccm.o
 obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
 obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
 obj-$(CONFIG_CRYPTO_DES) += des_generic.o
 obj-$(CONFIG_CRYPTO_DES) += des_generic.o
 obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
 obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
@@ -48,10 +56,12 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
 obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_SEED) += seed.o
 obj-$(CONFIG_CRYPTO_SEED) += seed.o
+obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
+obj-$(CONFIG_CRYPTO_LZO) += lzo.o
 
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
 

+ 239 - 2
crypto/ablkcipher.c

@@ -13,14 +13,18 @@
  *
  *
  */
  */
 
 
-#include <crypto/algapi.h>
-#include <linux/errno.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 
 
+#include "internal.h"
+
 static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key,
 static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key,
 			    unsigned int keylen)
 			    unsigned int keylen)
 {
 {
@@ -66,6 +70,16 @@ static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type,
 	return alg->cra_ctxsize;
 	return alg->cra_ctxsize;
 }
 }
 
 
+int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req)
+{
+	return crypto_ablkcipher_encrypt(&req->creq);
+}
+
+int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req)
+{
+	return crypto_ablkcipher_decrypt(&req->creq);
+}
+
 static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
 static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
 				      u32 mask)
 				      u32 mask)
 {
 {
@@ -78,6 +92,11 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
 	crt->setkey = setkey;
 	crt->setkey = setkey;
 	crt->encrypt = alg->encrypt;
 	crt->encrypt = alg->encrypt;
 	crt->decrypt = alg->decrypt;
 	crt->decrypt = alg->decrypt;
+	if (!alg->ivsize) {
+		crt->givencrypt = skcipher_null_givencrypt;
+		crt->givdecrypt = skcipher_null_givdecrypt;
+	}
+	crt->base = __crypto_ablkcipher_cast(tfm);
 	crt->ivsize = alg->ivsize;
 	crt->ivsize = alg->ivsize;
 
 
 	return 0;
 	return 0;
@@ -90,10 +109,13 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
 	struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
 	struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
 
 
 	seq_printf(m, "type         : ablkcipher\n");
 	seq_printf(m, "type         : ablkcipher\n");
+	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+					     "yes" : "no");
 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
 	seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
 	seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
 	seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
 	seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
 	seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
 	seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
+	seq_printf(m, "geniv        : %s\n", ablkcipher->geniv ?: "<default>");
 }
 }
 
 
 const struct crypto_type crypto_ablkcipher_type = {
 const struct crypto_type crypto_ablkcipher_type = {
@@ -105,5 +127,220 @@ const struct crypto_type crypto_ablkcipher_type = {
 };
 };
 EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);
 EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);
 
 
+static int no_givdecrypt(struct skcipher_givcrypt_request *req)
+{
+	return -ENOSYS;
+}
+
+static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type,
+				      u32 mask)
+{
+	struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher;
+	struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
+
+	if (alg->ivsize > PAGE_SIZE / 8)
+		return -EINVAL;
+
+	crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
+		      alg->setkey : setkey;
+	crt->encrypt = alg->encrypt;
+	crt->decrypt = alg->decrypt;
+	crt->givencrypt = alg->givencrypt;
+	crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt;
+	crt->base = __crypto_ablkcipher_cast(tfm);
+	crt->ivsize = alg->ivsize;
+
+	return 0;
+}
+
+static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
+
+	seq_printf(m, "type         : givcipher\n");
+	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+					     "yes" : "no");
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+	seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
+	seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
+	seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
+	seq_printf(m, "geniv        : %s\n", ablkcipher->geniv ?: "<built-in>");
+}
+
+const struct crypto_type crypto_givcipher_type = {
+	.ctxsize = crypto_ablkcipher_ctxsize,
+	.init = crypto_init_givcipher_ops,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_givcipher_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_givcipher_type);
+
+const char *crypto_default_geniv(const struct crypto_alg *alg)
+{
+	return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv";
+}
+
+static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
+{
+	struct rtattr *tb[3];
+	struct {
+		struct rtattr attr;
+		struct crypto_attr_type data;
+	} ptype;
+	struct {
+		struct rtattr attr;
+		struct crypto_attr_alg data;
+	} palg;
+	struct crypto_template *tmpl;
+	struct crypto_instance *inst;
+	struct crypto_alg *larval;
+	const char *geniv;
+	int err;
+
+	larval = crypto_larval_lookup(alg->cra_driver_name,
+				      CRYPTO_ALG_TYPE_GIVCIPHER,
+				      CRYPTO_ALG_TYPE_MASK);
+	err = PTR_ERR(larval);
+	if (IS_ERR(larval))
+		goto out;
+
+	err = -EAGAIN;
+	if (!crypto_is_larval(larval))
+		goto drop_larval;
+
+	ptype.attr.rta_len = sizeof(ptype);
+	ptype.attr.rta_type = CRYPTOA_TYPE;
+	ptype.data.type = type | CRYPTO_ALG_GENIV;
+	/* GENIV tells the template that we're making a default geniv. */
+	ptype.data.mask = mask | CRYPTO_ALG_GENIV;
+	tb[0] = &ptype.attr;
+
+	palg.attr.rta_len = sizeof(palg);
+	palg.attr.rta_type = CRYPTOA_ALG;
+	/* Must use the exact name to locate ourselves. */
+	memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME);
+	tb[1] = &palg.attr;
+
+	tb[2] = NULL;
+
+	if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+	    CRYPTO_ALG_TYPE_BLKCIPHER)
+		geniv = alg->cra_blkcipher.geniv;
+	else
+		geniv = alg->cra_ablkcipher.geniv;
+
+	if (!geniv)
+		geniv = crypto_default_geniv(alg);
+
+	tmpl = crypto_lookup_template(geniv);
+	err = -ENOENT;
+	if (!tmpl)
+		goto kill_larval;
+
+	inst = tmpl->alloc(tb);
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto put_tmpl;
+
+	if ((err = crypto_register_instance(tmpl, inst))) {
+		tmpl->free(inst);
+		goto put_tmpl;
+	}
+
+	/* Redo the lookup to use the instance we just registered. */
+	err = -EAGAIN;
+
+put_tmpl:
+	crypto_tmpl_put(tmpl);
+kill_larval:
+	crypto_larval_kill(larval);
+drop_larval:
+	crypto_mod_put(larval);
+out:
+	crypto_mod_put(alg);
+	return err;
+}
+
+static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type,
+						 u32 mask)
+{
+	struct crypto_alg *alg;
+
+	alg = crypto_alg_mod_lookup(name, type, mask);
+	if (IS_ERR(alg))
+		return alg;
+
+	if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+	    CRYPTO_ALG_TYPE_GIVCIPHER)
+		return alg;
+
+	if (!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+	      CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+					  alg->cra_ablkcipher.ivsize))
+		return alg;
+
+	return ERR_PTR(crypto_givcipher_default(alg, type, mask));
+}
+
+int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
+			 u32 type, u32 mask)
+{
+	struct crypto_alg *alg;
+	int err;
+
+	type = crypto_skcipher_type(type);
+	mask = crypto_skcipher_mask(mask);
+
+	alg = crypto_lookup_skcipher(name, type, mask);
+	if (IS_ERR(alg))
+		return PTR_ERR(alg);
+
+	err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+	crypto_mod_put(alg);
+	return err;
+}
+EXPORT_SYMBOL_GPL(crypto_grab_skcipher);
+
+struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name,
+						  u32 type, u32 mask)
+{
+	struct crypto_tfm *tfm;
+	int err;
+
+	type = crypto_skcipher_type(type);
+	mask = crypto_skcipher_mask(mask);
+
+	for (;;) {
+		struct crypto_alg *alg;
+
+		alg = crypto_lookup_skcipher(alg_name, type, mask);
+		if (IS_ERR(alg)) {
+			err = PTR_ERR(alg);
+			goto err;
+		}
+
+		tfm = __crypto_alloc_tfm(alg, type, mask);
+		if (!IS_ERR(tfm))
+			return __crypto_ablkcipher_cast(tfm);
+
+		crypto_mod_put(alg);
+		err = PTR_ERR(tfm);
+
+err:
+		if (err != -EAGAIN)
+			break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher);
+
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous block chaining cipher type");
 MODULE_DESCRIPTION("Asynchronous block chaining cipher type");

+ 394 - 6
crypto/aead.c

@@ -12,14 +12,17 @@
  *
  *
  */
  */
 
 
-#include <crypto/algapi.h>
-#include <linux/errno.h>
+#include <crypto/internal/aead.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 
 
+#include "internal.h"
+
 static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
 static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
 			    unsigned int keylen)
 			    unsigned int keylen)
 {
 {
@@ -53,25 +56,54 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
 	return aead->setkey(tfm, key, keylen);
 	return aead->setkey(tfm, key, keylen);
 }
 }
 
 
+int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+	struct aead_tfm *crt = crypto_aead_crt(tfm);
+	int err;
+
+	if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+		return -EINVAL;
+
+	if (crypto_aead_alg(tfm)->setauthsize) {
+		err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize);
+		if (err)
+			return err;
+	}
+
+	crypto_aead_crt(crt->base)->authsize = authsize;
+	crt->authsize = authsize;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
+
 static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type,
 static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type,
 					u32 mask)
 					u32 mask)
 {
 {
 	return alg->cra_ctxsize;
 	return alg->cra_ctxsize;
 }
 }
 
 
+static int no_givcrypt(struct aead_givcrypt_request *req)
+{
+	return -ENOSYS;
+}
+
 static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 {
 {
 	struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
 	struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
 	struct aead_tfm *crt = &tfm->crt_aead;
 	struct aead_tfm *crt = &tfm->crt_aead;
 
 
-	if (max(alg->authsize, alg->ivsize) > PAGE_SIZE / 8)
+	if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	crt->setkey = setkey;
+	crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
+		      alg->setkey : setkey;
 	crt->encrypt = alg->encrypt;
 	crt->encrypt = alg->encrypt;
 	crt->decrypt = alg->decrypt;
 	crt->decrypt = alg->decrypt;
+	crt->givencrypt = alg->givencrypt ?: no_givcrypt;
+	crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;
+	crt->base = __crypto_aead_cast(tfm);
 	crt->ivsize = alg->ivsize;
 	crt->ivsize = alg->ivsize;
-	crt->authsize = alg->authsize;
+	crt->authsize = alg->maxauthsize;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -83,9 +115,12 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
 	struct aead_alg *aead = &alg->cra_aead;
 	struct aead_alg *aead = &alg->cra_aead;
 
 
 	seq_printf(m, "type         : aead\n");
 	seq_printf(m, "type         : aead\n");
+	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+					     "yes" : "no");
 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
 	seq_printf(m, "ivsize       : %u\n", aead->ivsize);
 	seq_printf(m, "ivsize       : %u\n", aead->ivsize);
-	seq_printf(m, "authsize     : %u\n", aead->authsize);
+	seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
+	seq_printf(m, "geniv        : %s\n", aead->geniv ?: "<built-in>");
 }
 }
 
 
 const struct crypto_type crypto_aead_type = {
 const struct crypto_type crypto_aead_type = {
@@ -97,5 +132,358 @@ const struct crypto_type crypto_aead_type = {
 };
 };
 EXPORT_SYMBOL_GPL(crypto_aead_type);
 EXPORT_SYMBOL_GPL(crypto_aead_type);
 
 
+static int aead_null_givencrypt(struct aead_givcrypt_request *req)
+{
+	return crypto_aead_encrypt(&req->areq);
+}
+
+static int aead_null_givdecrypt(struct aead_givcrypt_request *req)
+{
+	return crypto_aead_decrypt(&req->areq);
+}
+
+static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+	struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
+	struct aead_tfm *crt = &tfm->crt_aead;
+
+	if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
+		return -EINVAL;
+
+	crt->setkey = setkey;
+	crt->encrypt = alg->encrypt;
+	crt->decrypt = alg->decrypt;
+	if (!alg->ivsize) {
+		crt->givencrypt = aead_null_givencrypt;
+		crt->givdecrypt = aead_null_givdecrypt;
+	}
+	crt->base = __crypto_aead_cast(tfm);
+	crt->ivsize = alg->ivsize;
+	crt->authsize = alg->maxauthsize;
+
+	return 0;
+}
+
+static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	struct aead_alg *aead = &alg->cra_aead;
+
+	seq_printf(m, "type         : nivaead\n");
+	seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+					     "yes" : "no");
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+	seq_printf(m, "ivsize       : %u\n", aead->ivsize);
+	seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
+	seq_printf(m, "geniv        : %s\n", aead->geniv);
+}
+
+const struct crypto_type crypto_nivaead_type = {
+	.ctxsize = crypto_aead_ctxsize,
+	.init = crypto_init_nivaead_ops,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_nivaead_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_nivaead_type);
+
+static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn,
+			       const char *name, u32 type, u32 mask)
+{
+	struct crypto_alg *alg;
+	int err;
+
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	type |= CRYPTO_ALG_TYPE_AEAD;
+	mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV;
+
+	alg = crypto_alg_mod_lookup(name, type, mask);
+	if (IS_ERR(alg))
+		return PTR_ERR(alg);
+
+	err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+	crypto_mod_put(alg);
+	return err;
+}
+
+struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
+					 struct rtattr **tb, u32 type,
+					 u32 mask)
+{
+	const char *name;
+	struct crypto_aead_spawn *spawn;
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) &
+	    algt->mask)
+		return ERR_PTR(-EINVAL);
+
+	name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(name);
+	if (IS_ERR(name))
+		return ERR_PTR(err);
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+	if (!inst)
+		return ERR_PTR(-ENOMEM);
+
+	spawn = crypto_instance_ctx(inst);
+
+	/* Ignore async algorithms if necessary. */
+	mask |= crypto_requires_sync(algt->type, algt->mask);
+
+	crypto_set_aead_spawn(spawn, inst);
+	err = crypto_grab_nivaead(spawn, name, type, mask);
+	if (err)
+		goto err_free_inst;
+
+	alg = crypto_aead_spawn_alg(spawn);
+
+	err = -EINVAL;
+	if (!alg->cra_aead.ivsize)
+		goto err_drop_alg;
+
+	/*
+	 * This is only true if we're constructing an algorithm with its
+	 * default IV generator.  For the default generator we elide the
+	 * template name and double-check the IV generator.
+	 */
+	if (algt->mask & CRYPTO_ALG_GENIV) {
+		if (strcmp(tmpl->name, alg->cra_aead.geniv))
+			goto err_drop_alg;
+
+		memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+		memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
+		       CRYPTO_MAX_ALG_NAME);
+	} else {
+		err = -ENAMETOOLONG;
+		if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+			     "%s(%s)", tmpl->name, alg->cra_name) >=
+		    CRYPTO_MAX_ALG_NAME)
+			goto err_drop_alg;
+		if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+			     "%s(%s)", tmpl->name, alg->cra_driver_name) >=
+		    CRYPTO_MAX_ALG_NAME)
+			goto err_drop_alg;
+	}
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV;
+	inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = alg->cra_blocksize;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_aead_type;
+
+	inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
+	inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
+	inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
+
+	inst->alg.cra_aead.setkey = alg->cra_aead.setkey;
+	inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
+	inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt;
+	inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt;
+
+out:
+	return inst;
+
+err_drop_alg:
+	crypto_drop_aead(spawn);
+err_free_inst:
+	kfree(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+EXPORT_SYMBOL_GPL(aead_geniv_alloc);
+
+void aead_geniv_free(struct crypto_instance *inst)
+{
+	crypto_drop_aead(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+EXPORT_SYMBOL_GPL(aead_geniv_free);
+
+int aead_geniv_init(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_aead *aead;
+
+	aead = crypto_spawn_aead(crypto_instance_ctx(inst));
+	if (IS_ERR(aead))
+		return PTR_ERR(aead);
+
+	tfm->crt_aead.base = aead;
+	tfm->crt_aead.reqsize += crypto_aead_reqsize(aead);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(aead_geniv_init);
+
+void aead_geniv_exit(struct crypto_tfm *tfm)
+{
+	crypto_free_aead(tfm->crt_aead.base);
+}
+EXPORT_SYMBOL_GPL(aead_geniv_exit);
+
+static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask)
+{
+	struct rtattr *tb[3];
+	struct {
+		struct rtattr attr;
+		struct crypto_attr_type data;
+	} ptype;
+	struct {
+		struct rtattr attr;
+		struct crypto_attr_alg data;
+	} palg;
+	struct crypto_template *tmpl;
+	struct crypto_instance *inst;
+	struct crypto_alg *larval;
+	const char *geniv;
+	int err;
+
+	larval = crypto_larval_lookup(alg->cra_driver_name,
+				      CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV,
+				      CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	err = PTR_ERR(larval);
+	if (IS_ERR(larval))
+		goto out;
+
+	err = -EAGAIN;
+	if (!crypto_is_larval(larval))
+		goto drop_larval;
+
+	ptype.attr.rta_len = sizeof(ptype);
+	ptype.attr.rta_type = CRYPTOA_TYPE;
+	ptype.data.type = type | CRYPTO_ALG_GENIV;
+	/* GENIV tells the template that we're making a default geniv. */
+	ptype.data.mask = mask | CRYPTO_ALG_GENIV;
+	tb[0] = &ptype.attr;
+
+	palg.attr.rta_len = sizeof(palg);
+	palg.attr.rta_type = CRYPTOA_ALG;
+	/* Must use the exact name to locate ourselves. */
+	memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME);
+	tb[1] = &palg.attr;
+
+	tb[2] = NULL;
+
+	geniv = alg->cra_aead.geniv;
+
+	tmpl = crypto_lookup_template(geniv);
+	err = -ENOENT;
+	if (!tmpl)
+		goto kill_larval;
+
+	inst = tmpl->alloc(tb);
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto put_tmpl;
+
+	if ((err = crypto_register_instance(tmpl, inst))) {
+		tmpl->free(inst);
+		goto put_tmpl;
+	}
+
+	/* Redo the lookup to use the instance we just registered. */
+	err = -EAGAIN;
+
+put_tmpl:
+	crypto_tmpl_put(tmpl);
+kill_larval:
+	crypto_larval_kill(larval);
+drop_larval:
+	crypto_mod_put(larval);
+out:
+	crypto_mod_put(alg);
+	return err;
+}
+
+static struct crypto_alg *crypto_lookup_aead(const char *name, u32 type,
+					     u32 mask)
+{
+	struct crypto_alg *alg;
+
+	alg = crypto_alg_mod_lookup(name, type, mask);
+	if (IS_ERR(alg))
+		return alg;
+
+	if (alg->cra_type == &crypto_aead_type)
+		return alg;
+
+	if (!alg->cra_aead.ivsize)
+		return alg;
+
+	return ERR_PTR(crypto_nivaead_default(alg, type, mask));
+}
+
+int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
+		     u32 type, u32 mask)
+{
+	struct crypto_alg *alg;
+	int err;
+
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	type |= CRYPTO_ALG_TYPE_AEAD;
+	mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	mask |= CRYPTO_ALG_TYPE_MASK;
+
+	alg = crypto_lookup_aead(name, type, mask);
+	if (IS_ERR(alg))
+		return PTR_ERR(alg);
+
+	err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+	crypto_mod_put(alg);
+	return err;
+}
+EXPORT_SYMBOL_GPL(crypto_grab_aead);
+
+struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
+{
+	struct crypto_tfm *tfm;
+	int err;
+
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	type |= CRYPTO_ALG_TYPE_AEAD;
+	mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	mask |= CRYPTO_ALG_TYPE_MASK;
+
+	for (;;) {
+		struct crypto_alg *alg;
+
+		alg = crypto_lookup_aead(alg_name, type, mask);
+		if (IS_ERR(alg)) {
+			err = PTR_ERR(alg);
+			goto err;
+		}
+
+		tfm = __crypto_alloc_tfm(alg, type, mask);
+		if (!IS_ERR(tfm))
+			return __crypto_aead_cast(tfm);
+
+		crypto_mod_put(alg);
+		err = PTR_ERR(tfm);
+
+err:
+		if (err != -EAGAIN)
+			break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_aead);
+
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
 MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");

+ 241 - 227
crypto/aes_generic.c

@@ -47,11 +47,7 @@
  * ---------------------------------------------------------------------------
  * ---------------------------------------------------------------------------
  */
  */
 
 
-/* Some changes from the Gladman version:
-    s/RIJNDAEL(e_key)/E_KEY/g
-    s/RIJNDAEL(d_key)/D_KEY/g
-*/
-
+#include <crypto/aes.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/types.h>
@@ -59,88 +55,46 @@
 #include <linux/crypto.h>
 #include <linux/crypto.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 
 
-#define AES_MIN_KEY_SIZE	16
-#define AES_MAX_KEY_SIZE	32
-
-#define AES_BLOCK_SIZE		16
-
-/*
- * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) 
- */
-static inline u8
-byte(const u32 x, const unsigned n)
+static inline u8 byte(const u32 x, const unsigned n)
 {
 {
 	return x >> (n << 3);
 	return x >> (n << 3);
 }
 }
 
 
-struct aes_ctx {
-	int key_length;
-	u32 buf[120];
-};
-
-#define E_KEY (&ctx->buf[0])
-#define D_KEY (&ctx->buf[60])
-
 static u8 pow_tab[256] __initdata;
 static u8 pow_tab[256] __initdata;
 static u8 log_tab[256] __initdata;
 static u8 log_tab[256] __initdata;
 static u8 sbx_tab[256] __initdata;
 static u8 sbx_tab[256] __initdata;
 static u8 isb_tab[256] __initdata;
 static u8 isb_tab[256] __initdata;
 static u32 rco_tab[10];
 static u32 rco_tab[10];
-static u32 ft_tab[4][256];
-static u32 it_tab[4][256];
 
 
-static u32 fl_tab[4][256];
-static u32 il_tab[4][256];
+u32 crypto_ft_tab[4][256];
+u32 crypto_fl_tab[4][256];
+u32 crypto_it_tab[4][256];
+u32 crypto_il_tab[4][256];
 
 
-static inline u8 __init
-f_mult (u8 a, u8 b)
+EXPORT_SYMBOL_GPL(crypto_ft_tab);
+EXPORT_SYMBOL_GPL(crypto_fl_tab);
+EXPORT_SYMBOL_GPL(crypto_it_tab);
+EXPORT_SYMBOL_GPL(crypto_il_tab);
+
+static inline u8 __init f_mult(u8 a, u8 b)
 {
 {
 	u8 aa = log_tab[a], cc = aa + log_tab[b];
 	u8 aa = log_tab[a], cc = aa + log_tab[b];
 
 
 	return pow_tab[cc + (cc < aa ? 1 : 0)];
 	return pow_tab[cc + (cc < aa ? 1 : 0)];
 }
 }
 
 
-#define ff_mult(a,b)    (a && b ? f_mult(a, b) : 0)
-
-#define f_rn(bo, bi, n, k)					\
-    bo[n] =  ft_tab[0][byte(bi[n],0)] ^				\
-             ft_tab[1][byte(bi[(n + 1) & 3],1)] ^		\
-             ft_tab[2][byte(bi[(n + 2) & 3],2)] ^		\
-             ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-
-#define i_rn(bo, bi, n, k)					\
-    bo[n] =  it_tab[0][byte(bi[n],0)] ^				\
-             it_tab[1][byte(bi[(n + 3) & 3],1)] ^		\
-             it_tab[2][byte(bi[(n + 2) & 3],2)] ^		\
-             it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-
-#define ls_box(x)				\
-    ( fl_tab[0][byte(x, 0)] ^			\
-      fl_tab[1][byte(x, 1)] ^			\
-      fl_tab[2][byte(x, 2)] ^			\
-      fl_tab[3][byte(x, 3)] )
-
-#define f_rl(bo, bi, n, k)					\
-    bo[n] =  fl_tab[0][byte(bi[n],0)] ^				\
-             fl_tab[1][byte(bi[(n + 1) & 3],1)] ^		\
-             fl_tab[2][byte(bi[(n + 2) & 3],2)] ^		\
-             fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
-
-#define i_rl(bo, bi, n, k)					\
-    bo[n] =  il_tab[0][byte(bi[n],0)] ^				\
-             il_tab[1][byte(bi[(n + 3) & 3],1)] ^		\
-             il_tab[2][byte(bi[(n + 2) & 3],2)] ^		\
-             il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
-
-static void __init
-gen_tabs (void)
+#define ff_mult(a, b)	(a && b ? f_mult(a, b) : 0)
+
+static void __init gen_tabs(void)
 {
 {
 	u32 i, t;
 	u32 i, t;
 	u8 p, q;
 	u8 p, q;
 
 
-	/* log and power tables for GF(2**8) finite field with
-	   0x011b as modular polynomial - the simplest primitive
-	   root is 0x03, used here to generate the tables */
+	/*
+	 * log and power tables for GF(2**8) finite field with
+	 * 0x011b as modular polynomial - the simplest primitive
+	 * root is 0x03, used here to generate the tables
+	 */
 
 
 	for (i = 0, p = 1; i < 256; ++i) {
 	for (i = 0, p = 1; i < 256; ++i) {
 		pow_tab[i] = (u8) p;
 		pow_tab[i] = (u8) p;
@@ -169,92 +123,119 @@ gen_tabs (void)
 		p = sbx_tab[i];
 		p = sbx_tab[i];
 
 
 		t = p;
 		t = p;
-		fl_tab[0][i] = t;
-		fl_tab[1][i] = rol32(t, 8);
-		fl_tab[2][i] = rol32(t, 16);
-		fl_tab[3][i] = rol32(t, 24);
+		crypto_fl_tab[0][i] = t;
+		crypto_fl_tab[1][i] = rol32(t, 8);
+		crypto_fl_tab[2][i] = rol32(t, 16);
+		crypto_fl_tab[3][i] = rol32(t, 24);
 
 
-		t = ((u32) ff_mult (2, p)) |
+		t = ((u32) ff_mult(2, p)) |
 		    ((u32) p << 8) |
 		    ((u32) p << 8) |
-		    ((u32) p << 16) | ((u32) ff_mult (3, p) << 24);
+		    ((u32) p << 16) | ((u32) ff_mult(3, p) << 24);
 
 
-		ft_tab[0][i] = t;
-		ft_tab[1][i] = rol32(t, 8);
-		ft_tab[2][i] = rol32(t, 16);
-		ft_tab[3][i] = rol32(t, 24);
+		crypto_ft_tab[0][i] = t;
+		crypto_ft_tab[1][i] = rol32(t, 8);
+		crypto_ft_tab[2][i] = rol32(t, 16);
+		crypto_ft_tab[3][i] = rol32(t, 24);
 
 
 		p = isb_tab[i];
 		p = isb_tab[i];
 
 
 		t = p;
 		t = p;
-		il_tab[0][i] = t;
-		il_tab[1][i] = rol32(t, 8);
-		il_tab[2][i] = rol32(t, 16);
-		il_tab[3][i] = rol32(t, 24);
-
-		t = ((u32) ff_mult (14, p)) |
-		    ((u32) ff_mult (9, p) << 8) |
-		    ((u32) ff_mult (13, p) << 16) |
-		    ((u32) ff_mult (11, p) << 24);
-
-		it_tab[0][i] = t;
-		it_tab[1][i] = rol32(t, 8);
-		it_tab[2][i] = rol32(t, 16);
-		it_tab[3][i] = rol32(t, 24);
+		crypto_il_tab[0][i] = t;
+		crypto_il_tab[1][i] = rol32(t, 8);
+		crypto_il_tab[2][i] = rol32(t, 16);
+		crypto_il_tab[3][i] = rol32(t, 24);
+
+		t = ((u32) ff_mult(14, p)) |
+		    ((u32) ff_mult(9, p) << 8) |
+		    ((u32) ff_mult(13, p) << 16) |
+		    ((u32) ff_mult(11, p) << 24);
+
+		crypto_it_tab[0][i] = t;
+		crypto_it_tab[1][i] = rol32(t, 8);
+		crypto_it_tab[2][i] = rol32(t, 16);
+		crypto_it_tab[3][i] = rol32(t, 24);
 	}
 	}
 }
 }
 
 
-#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
-
-#define imix_col(y,x)       \
-    u   = star_x(x);        \
-    v   = star_x(u);        \
-    w   = star_x(v);        \
-    t   = w ^ (x);          \
-   (y)  = u ^ v ^ w;        \
-   (y) ^= ror32(u ^ t,  8) ^ \
-          ror32(v ^ t, 16) ^ \
-          ror32(t,24)
-
 /* initialise the key schedule from the user supplied key */
 /* initialise the key schedule from the user supplied key */
 
 
-#define loop4(i)                                    \
-{   t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];    \
-    t ^= E_KEY[4 * i];     E_KEY[4 * i + 4] = t;    \
-    t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t;    \
-    t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t;    \
-    t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t;    \
-}
-
-#define loop6(i)                                    \
-{   t = ror32(t,  8); t = ls_box(t) ^ rco_tab[i];    \
-    t ^= E_KEY[6 * i];     E_KEY[6 * i + 6] = t;    \
-    t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t;    \
-    t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t;    \
-    t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t;    \
-    t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t;   \
-    t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t;   \
-}
-
-#define loop8(i)                                    \
-{   t = ror32(t,  8); ; t = ls_box(t) ^ rco_tab[i];  \
-    t ^= E_KEY[8 * i];     E_KEY[8 * i + 8] = t;    \
-    t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t;    \
-    t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t;   \
-    t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t;   \
-    t  = E_KEY[8 * i + 4] ^ ls_box(t);    \
-    E_KEY[8 * i + 12] = t;                \
-    t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t;   \
-    t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t;   \
-    t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;   \
-}
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
 
 
-static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-		       unsigned int key_len)
+#define imix_col(y,x)	do {		\
+	u	= star_x(x);		\
+	v	= star_x(u);		\
+	w	= star_x(v);		\
+	t	= w ^ (x);		\
+	(y)	= u ^ v ^ w;		\
+	(y)	^= ror32(u ^ t, 8) ^	\
+		ror32(v ^ t, 16) ^	\
+		ror32(t, 24);		\
+} while (0)
+
+#define ls_box(x)		\
+	crypto_fl_tab[0][byte(x, 0)] ^	\
+	crypto_fl_tab[1][byte(x, 1)] ^	\
+	crypto_fl_tab[2][byte(x, 2)] ^	\
+	crypto_fl_tab[3][byte(x, 3)]
+
+#define loop4(i)	do {		\
+	t = ror32(t, 8);		\
+	t = ls_box(t) ^ rco_tab[i];	\
+	t ^= ctx->key_enc[4 * i];		\
+	ctx->key_enc[4 * i + 4] = t;		\
+	t ^= ctx->key_enc[4 * i + 1];		\
+	ctx->key_enc[4 * i + 5] = t;		\
+	t ^= ctx->key_enc[4 * i + 2];		\
+	ctx->key_enc[4 * i + 6] = t;		\
+	t ^= ctx->key_enc[4 * i + 3];		\
+	ctx->key_enc[4 * i + 7] = t;		\
+} while (0)
+
+#define loop6(i)	do {		\
+	t = ror32(t, 8);		\
+	t = ls_box(t) ^ rco_tab[i];	\
+	t ^= ctx->key_enc[6 * i];		\
+	ctx->key_enc[6 * i + 6] = t;		\
+	t ^= ctx->key_enc[6 * i + 1];		\
+	ctx->key_enc[6 * i + 7] = t;		\
+	t ^= ctx->key_enc[6 * i + 2];		\
+	ctx->key_enc[6 * i + 8] = t;		\
+	t ^= ctx->key_enc[6 * i + 3];		\
+	ctx->key_enc[6 * i + 9] = t;		\
+	t ^= ctx->key_enc[6 * i + 4];		\
+	ctx->key_enc[6 * i + 10] = t;		\
+	t ^= ctx->key_enc[6 * i + 5];		\
+	ctx->key_enc[6 * i + 11] = t;		\
+} while (0)
+
+#define loop8(i)	do {			\
+	t = ror32(t, 8);			\
+	t = ls_box(t) ^ rco_tab[i];		\
+	t ^= ctx->key_enc[8 * i];			\
+	ctx->key_enc[8 * i + 8] = t;			\
+	t ^= ctx->key_enc[8 * i + 1];			\
+	ctx->key_enc[8 * i + 9] = t;			\
+	t ^= ctx->key_enc[8 * i + 2];			\
+	ctx->key_enc[8 * i + 10] = t;			\
+	t ^= ctx->key_enc[8 * i + 3];			\
+	ctx->key_enc[8 * i + 11] = t;			\
+	t  = ctx->key_enc[8 * i + 4] ^ ls_box(t);	\
+	ctx->key_enc[8 * i + 12] = t;			\
+	t ^= ctx->key_enc[8 * i + 5];			\
+	ctx->key_enc[8 * i + 13] = t;			\
+	t ^= ctx->key_enc[8 * i + 6];			\
+	ctx->key_enc[8 * i + 14] = t;			\
+	t ^= ctx->key_enc[8 * i + 7];			\
+	ctx->key_enc[8 * i + 15] = t;			\
+} while (0)
+
+int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		unsigned int key_len)
 {
 {
-	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 	const __le32 *key = (const __le32 *)in_key;
 	u32 *flags = &tfm->crt_flags;
 	u32 *flags = &tfm->crt_flags;
-	u32 i, t, u, v, w;
+	u32 i, t, u, v, w, j;
 
 
 	if (key_len % 8) {
 	if (key_len % 8) {
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -263,95 +244,113 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
 
 	ctx->key_length = key_len;
 	ctx->key_length = key_len;
 
 
-	E_KEY[0] = le32_to_cpu(key[0]);
-	E_KEY[1] = le32_to_cpu(key[1]);
-	E_KEY[2] = le32_to_cpu(key[2]);
-	E_KEY[3] = le32_to_cpu(key[3]);
+	ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]);
+	ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]);
+	ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]);
+	ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]);
 
 
 	switch (key_len) {
 	switch (key_len) {
 	case 16:
 	case 16:
-		t = E_KEY[3];
+		t = ctx->key_enc[3];
 		for (i = 0; i < 10; ++i)
 		for (i = 0; i < 10; ++i)
-			loop4 (i);
+			loop4(i);
 		break;
 		break;
 
 
 	case 24:
 	case 24:
-		E_KEY[4] = le32_to_cpu(key[4]);
-		t = E_KEY[5] = le32_to_cpu(key[5]);
+		ctx->key_enc[4] = le32_to_cpu(key[4]);
+		t = ctx->key_enc[5] = le32_to_cpu(key[5]);
 		for (i = 0; i < 8; ++i)
 		for (i = 0; i < 8; ++i)
-			loop6 (i);
+			loop6(i);
 		break;
 		break;
 
 
 	case 32:
 	case 32:
-		E_KEY[4] = le32_to_cpu(key[4]);
-		E_KEY[5] = le32_to_cpu(key[5]);
-		E_KEY[6] = le32_to_cpu(key[6]);
-		t = E_KEY[7] = le32_to_cpu(key[7]);
+		ctx->key_enc[4] = le32_to_cpu(key[4]);
+		ctx->key_enc[5] = le32_to_cpu(key[5]);
+		ctx->key_enc[6] = le32_to_cpu(key[6]);
+		t = ctx->key_enc[7] = le32_to_cpu(key[7]);
 		for (i = 0; i < 7; ++i)
 		for (i = 0; i < 7; ++i)
-			loop8 (i);
+			loop8(i);
 		break;
 		break;
 	}
 	}
 
 
-	D_KEY[0] = E_KEY[0];
-	D_KEY[1] = E_KEY[1];
-	D_KEY[2] = E_KEY[2];
-	D_KEY[3] = E_KEY[3];
+	ctx->key_dec[0] = ctx->key_enc[key_len + 24];
+	ctx->key_dec[1] = ctx->key_enc[key_len + 25];
+	ctx->key_dec[2] = ctx->key_enc[key_len + 26];
+	ctx->key_dec[3] = ctx->key_enc[key_len + 27];
 
 
 	for (i = 4; i < key_len + 24; ++i) {
 	for (i = 4; i < key_len + 24; ++i) {
-		imix_col (D_KEY[i], E_KEY[i]);
+		j = key_len + 24 - (i & ~3) + (i & 3);
+		imix_col(ctx->key_dec[j], ctx->key_enc[i]);
 	}
 	}
-
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(crypto_aes_set_key);
 
 
 /* encrypt a block of text */
 /* encrypt a block of text */
 
 
-#define f_nround(bo, bi, k) \
-    f_rn(bo, bi, 0, k);     \
-    f_rn(bo, bi, 1, k);     \
-    f_rn(bo, bi, 2, k);     \
-    f_rn(bo, bi, 3, k);     \
-    k += 4
-
-#define f_lround(bo, bi, k) \
-    f_rl(bo, bi, 0, k);     \
-    f_rl(bo, bi, 1, k);     \
-    f_rl(bo, bi, 2, k);     \
-    f_rl(bo, bi, 3, k)
+#define f_rn(bo, bi, n, k)	do {				\
+	bo[n] = crypto_ft_tab[0][byte(bi[n], 0)] ^			\
+		crypto_ft_tab[1][byte(bi[(n + 1) & 3], 1)] ^		\
+		crypto_ft_tab[2][byte(bi[(n + 2) & 3], 2)] ^		\
+		crypto_ft_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n);	\
+} while (0)
+
+#define f_nround(bo, bi, k)	do {\
+	f_rn(bo, bi, 0, k);	\
+	f_rn(bo, bi, 1, k);	\
+	f_rn(bo, bi, 2, k);	\
+	f_rn(bo, bi, 3, k);	\
+	k += 4;			\
+} while (0)
+
+#define f_rl(bo, bi, n, k)	do {				\
+	bo[n] = crypto_fl_tab[0][byte(bi[n], 0)] ^			\
+		crypto_fl_tab[1][byte(bi[(n + 1) & 3], 1)] ^		\
+		crypto_fl_tab[2][byte(bi[(n + 2) & 3], 2)] ^		\
+		crypto_fl_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n);	\
+} while (0)
+
+#define f_lround(bo, bi, k)	do {\
+	f_rl(bo, bi, 0, k);	\
+	f_rl(bo, bi, 1, k);	\
+	f_rl(bo, bi, 2, k);	\
+	f_rl(bo, bi, 3, k);	\
+} while (0)
 
 
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
-	const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *src = (const __le32 *)in;
 	const __le32 *src = (const __le32 *)in;
 	__le32 *dst = (__le32 *)out;
 	__le32 *dst = (__le32 *)out;
 	u32 b0[4], b1[4];
 	u32 b0[4], b1[4];
-	const u32 *kp = E_KEY + 4;
+	const u32 *kp = ctx->key_enc + 4;
+	const int key_len = ctx->key_length;
 
 
-	b0[0] = le32_to_cpu(src[0]) ^ E_KEY[0];
-	b0[1] = le32_to_cpu(src[1]) ^ E_KEY[1];
-	b0[2] = le32_to_cpu(src[2]) ^ E_KEY[2];
-	b0[3] = le32_to_cpu(src[3]) ^ E_KEY[3];
+	b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0];
+	b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1];
+	b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2];
+	b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3];
 
 
-	if (ctx->key_length > 24) {
-		f_nround (b1, b0, kp);
-		f_nround (b0, b1, kp);
+	if (key_len > 24) {
+		f_nround(b1, b0, kp);
+		f_nround(b0, b1, kp);
 	}
 	}
 
 
-	if (ctx->key_length > 16) {
-		f_nround (b1, b0, kp);
-		f_nround (b0, b1, kp);
+	if (key_len > 16) {
+		f_nround(b1, b0, kp);
+		f_nround(b0, b1, kp);
 	}
 	}
 
 
-	f_nround (b1, b0, kp);
-	f_nround (b0, b1, kp);
-	f_nround (b1, b0, kp);
-	f_nround (b0, b1, kp);
-	f_nround (b1, b0, kp);
-	f_nround (b0, b1, kp);
-	f_nround (b1, b0, kp);
-	f_nround (b0, b1, kp);
-	f_nround (b1, b0, kp);
-	f_lround (b0, b1, kp);
+	f_nround(b1, b0, kp);
+	f_nround(b0, b1, kp);
+	f_nround(b1, b0, kp);
+	f_nround(b0, b1, kp);
+	f_nround(b1, b0, kp);
+	f_nround(b0, b1, kp);
+	f_nround(b1, b0, kp);
+	f_nround(b0, b1, kp);
+	f_nround(b1, b0, kp);
+	f_lround(b0, b1, kp);
 
 
 	dst[0] = cpu_to_le32(b0[0]);
 	dst[0] = cpu_to_le32(b0[0]);
 	dst[1] = cpu_to_le32(b0[1]);
 	dst[1] = cpu_to_le32(b0[1]);
@@ -361,53 +360,69 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 
 
 /* decrypt a block of text */
 /* decrypt a block of text */
 
 
-#define i_nround(bo, bi, k) \
-    i_rn(bo, bi, 0, k);     \
-    i_rn(bo, bi, 1, k);     \
-    i_rn(bo, bi, 2, k);     \
-    i_rn(bo, bi, 3, k);     \
-    k -= 4
-
-#define i_lround(bo, bi, k) \
-    i_rl(bo, bi, 0, k);     \
-    i_rl(bo, bi, 1, k);     \
-    i_rl(bo, bi, 2, k);     \
-    i_rl(bo, bi, 3, k)
+#define i_rn(bo, bi, n, k)	do {				\
+	bo[n] = crypto_it_tab[0][byte(bi[n], 0)] ^			\
+		crypto_it_tab[1][byte(bi[(n + 3) & 3], 1)] ^		\
+		crypto_it_tab[2][byte(bi[(n + 2) & 3], 2)] ^		\
+		crypto_it_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n);	\
+} while (0)
+
+#define i_nround(bo, bi, k)	do {\
+	i_rn(bo, bi, 0, k);	\
+	i_rn(bo, bi, 1, k);	\
+	i_rn(bo, bi, 2, k);	\
+	i_rn(bo, bi, 3, k);	\
+	k += 4;			\
+} while (0)
+
+#define i_rl(bo, bi, n, k)	do {			\
+	bo[n] = crypto_il_tab[0][byte(bi[n], 0)] ^		\
+	crypto_il_tab[1][byte(bi[(n + 3) & 3], 1)] ^		\
+	crypto_il_tab[2][byte(bi[(n + 2) & 3], 2)] ^		\
+	crypto_il_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n);	\
+} while (0)
+
+#define i_lround(bo, bi, k)	do {\
+	i_rl(bo, bi, 0, k);	\
+	i_rl(bo, bi, 1, k);	\
+	i_rl(bo, bi, 2, k);	\
+	i_rl(bo, bi, 3, k);	\
+} while (0)
 
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
-	const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *src = (const __le32 *)in;
 	const __le32 *src = (const __le32 *)in;
 	__le32 *dst = (__le32 *)out;
 	__le32 *dst = (__le32 *)out;
 	u32 b0[4], b1[4];
 	u32 b0[4], b1[4];
 	const int key_len = ctx->key_length;
 	const int key_len = ctx->key_length;
-	const u32 *kp = D_KEY + key_len + 20;
+	const u32 *kp = ctx->key_dec + 4;
 
 
-	b0[0] = le32_to_cpu(src[0]) ^ E_KEY[key_len + 24];
-	b0[1] = le32_to_cpu(src[1]) ^ E_KEY[key_len + 25];
-	b0[2] = le32_to_cpu(src[2]) ^ E_KEY[key_len + 26];
-	b0[3] = le32_to_cpu(src[3]) ^ E_KEY[key_len + 27];
+	b0[0] = le32_to_cpu(src[0]) ^  ctx->key_dec[0];
+	b0[1] = le32_to_cpu(src[1]) ^  ctx->key_dec[1];
+	b0[2] = le32_to_cpu(src[2]) ^  ctx->key_dec[2];
+	b0[3] = le32_to_cpu(src[3]) ^  ctx->key_dec[3];
 
 
 	if (key_len > 24) {
 	if (key_len > 24) {
-		i_nround (b1, b0, kp);
-		i_nround (b0, b1, kp);
+		i_nround(b1, b0, kp);
+		i_nround(b0, b1, kp);
 	}
 	}
 
 
 	if (key_len > 16) {
 	if (key_len > 16) {
-		i_nround (b1, b0, kp);
-		i_nround (b0, b1, kp);
+		i_nround(b1, b0, kp);
+		i_nround(b0, b1, kp);
 	}
 	}
 
 
-	i_nround (b1, b0, kp);
-	i_nround (b0, b1, kp);
-	i_nround (b1, b0, kp);
-	i_nround (b0, b1, kp);
-	i_nround (b1, b0, kp);
-	i_nround (b0, b1, kp);
-	i_nround (b1, b0, kp);
-	i_nround (b0, b1, kp);
-	i_nround (b1, b0, kp);
-	i_lround (b0, b1, kp);
+	i_nround(b1, b0, kp);
+	i_nround(b0, b1, kp);
+	i_nround(b1, b0, kp);
+	i_nround(b0, b1, kp);
+	i_nround(b1, b0, kp);
+	i_nround(b0, b1, kp);
+	i_nround(b1, b0, kp);
+	i_nround(b0, b1, kp);
+	i_nround(b1, b0, kp);
+	i_lround(b0, b1, kp);
 
 
 	dst[0] = cpu_to_le32(b0[0]);
 	dst[0] = cpu_to_le32(b0[0]);
 	dst[1] = cpu_to_le32(b0[1]);
 	dst[1] = cpu_to_le32(b0[1]);
@@ -415,14 +430,13 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 	dst[3] = cpu_to_le32(b0[3]);
 	dst[3] = cpu_to_le32(b0[3]);
 }
 }
 
 
-
 static struct crypto_alg aes_alg = {
 static struct crypto_alg aes_alg = {
 	.cra_name		=	"aes",
 	.cra_name		=	"aes",
 	.cra_driver_name	=	"aes-generic",
 	.cra_driver_name	=	"aes-generic",
 	.cra_priority		=	100,
 	.cra_priority		=	100,
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
-	.cra_ctxsize		=	sizeof(struct aes_ctx),
+	.cra_ctxsize		=	sizeof(struct crypto_aes_ctx),
 	.cra_alignmask		=	3,
 	.cra_alignmask		=	3,
 	.cra_module		=	THIS_MODULE,
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
 	.cra_list		=	LIST_HEAD_INIT(aes_alg.cra_list),
@@ -430,9 +444,9 @@ static struct crypto_alg aes_alg = {
 		.cipher = {
 		.cipher = {
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
 			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
 			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
 			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
-			.cia_setkey	   	= 	aes_set_key,
-			.cia_encrypt	 	=	aes_encrypt,
-			.cia_decrypt	  	=	aes_decrypt
+			.cia_setkey		=	crypto_aes_set_key,
+			.cia_encrypt		=	aes_encrypt,
+			.cia_decrypt		=	aes_decrypt
 		}
 		}
 	}
 	}
 };
 };

+ 63 - 2
crypto/algapi.c

@@ -472,7 +472,7 @@ int crypto_check_attr_type(struct rtattr **tb, u32 type)
 }
 }
 EXPORT_SYMBOL_GPL(crypto_check_attr_type);
 EXPORT_SYMBOL_GPL(crypto_check_attr_type);
 
 
-struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+const char *crypto_attr_alg_name(struct rtattr *rta)
 {
 {
 	struct crypto_attr_alg *alga;
 	struct crypto_attr_alg *alga;
 
 
@@ -486,7 +486,21 @@ struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
 	alga = RTA_DATA(rta);
 	alga = RTA_DATA(rta);
 	alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
 	alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
 
 
-	return crypto_alg_mod_lookup(alga->name, type, mask);
+	return alga->name;
+}
+EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
+
+struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
+{
+	const char *name;
+	int err;
+
+	name = crypto_attr_alg_name(rta);
+	err = PTR_ERR(name);
+	if (IS_ERR(name))
+		return ERR_PTR(err);
+
+	return crypto_alg_mod_lookup(name, type, mask);
 }
 }
 EXPORT_SYMBOL_GPL(crypto_attr_alg);
 EXPORT_SYMBOL_GPL(crypto_attr_alg);
 
 
@@ -605,6 +619,53 @@ int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
 }
 }
 EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
 EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
 
 
+static inline void crypto_inc_byte(u8 *a, unsigned int size)
+{
+	u8 *b = (a + size);
+	u8 c;
+
+	for (; size; size--) {
+		c = *--b + 1;
+		*b = c;
+		if (c)
+			break;
+	}
+}
+
+void crypto_inc(u8 *a, unsigned int size)
+{
+	__be32 *b = (__be32 *)(a + size);
+	u32 c;
+
+	for (; size >= 4; size -= 4) {
+		c = be32_to_cpu(*--b) + 1;
+		*b = cpu_to_be32(c);
+		if (c)
+			return;
+	}
+
+	crypto_inc_byte(a, size);
+}
+EXPORT_SYMBOL_GPL(crypto_inc);
+
+static inline void crypto_xor_byte(u8 *a, const u8 *b, unsigned int size)
+{
+	for (; size; size--)
+		*a++ ^= *b++;
+}
+
+void crypto_xor(u8 *dst, const u8 *src, unsigned int size)
+{
+	u32 *a = (u32 *)dst;
+	u32 *b = (u32 *)src;
+
+	for (; size >= 4; size -= 4)
+		*a++ ^= *b++;
+
+	crypto_xor_byte((u8 *)a, (u8 *)b, size);
+}
+EXPORT_SYMBOL_GPL(crypto_xor);
+
 static int __init crypto_algapi_init(void)
 static int __init crypto_algapi_init(void)
 {
 {
 	crypto_init_proc();
 	crypto_init_proc();

+ 14 - 5
crypto/api.c

@@ -137,7 +137,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type,
 	return alg;
 	return alg;
 }
 }
 
 
-static void crypto_larval_kill(struct crypto_alg *alg)
+void crypto_larval_kill(struct crypto_alg *alg)
 {
 {
 	struct crypto_larval *larval = (void *)alg;
 	struct crypto_larval *larval = (void *)alg;
 
 
@@ -147,6 +147,7 @@ static void crypto_larval_kill(struct crypto_alg *alg)
 	complete_all(&larval->completion);
 	complete_all(&larval->completion);
 	crypto_alg_put(alg);
 	crypto_alg_put(alg);
 }
 }
+EXPORT_SYMBOL_GPL(crypto_larval_kill);
 
 
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
 {
 {
@@ -176,11 +177,9 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
 	return alg;
 	return alg;
 }
 }
 
 
-struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
 {
 {
 	struct crypto_alg *alg;
 	struct crypto_alg *alg;
-	struct crypto_alg *larval;
-	int ok;
 
 
 	if (!name)
 	if (!name)
 		return ERR_PTR(-ENOENT);
 		return ERR_PTR(-ENOENT);
@@ -193,7 +192,17 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
 	if (alg)
 	if (alg)
 		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
 		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
 
 
-	larval = crypto_larval_alloc(name, type, mask);
+	return crypto_larval_alloc(name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_larval_lookup);
+
+struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+{
+	struct crypto_alg *alg;
+	struct crypto_alg *larval;
+	int ok;
+
+	larval = crypto_larval_lookup(name, type, mask);
 	if (IS_ERR(larval) || !crypto_is_larval(larval))
 	if (IS_ERR(larval) || !crypto_is_larval(larval))
 		return larval;
 		return larval;
 
 

+ 213 - 121
crypto/authenc.c

@@ -10,22 +10,21 @@
  *
  *
  */
  */
 
 
-#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 
 
-#include "scatterwalk.h"
-
 struct authenc_instance_ctx {
 struct authenc_instance_ctx {
 	struct crypto_spawn auth;
 	struct crypto_spawn auth;
-	struct crypto_spawn enc;
-
-	unsigned int authsize;
-	unsigned int enckeylen;
+	struct crypto_skcipher_spawn enc;
 };
 };
 
 
 struct crypto_authenc_ctx {
 struct crypto_authenc_ctx {
@@ -37,19 +36,31 @@ struct crypto_authenc_ctx {
 static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 				 unsigned int keylen)
 				 unsigned int keylen)
 {
 {
-	struct authenc_instance_ctx *ictx =
-		crypto_instance_ctx(crypto_aead_alg_instance(authenc));
-	unsigned int enckeylen = ictx->enckeylen;
 	unsigned int authkeylen;
 	unsigned int authkeylen;
+	unsigned int enckeylen;
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_hash *auth = ctx->auth;
 	struct crypto_hash *auth = ctx->auth;
 	struct crypto_ablkcipher *enc = ctx->enc;
 	struct crypto_ablkcipher *enc = ctx->enc;
+	struct rtattr *rta = (void *)key;
+	struct crypto_authenc_key_param *param;
 	int err = -EINVAL;
 	int err = -EINVAL;
 
 
-	if (keylen < enckeylen) {
-		crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
-		goto out;
-	}
+	if (!RTA_OK(rta, keylen))
+		goto badkey;
+	if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+		goto badkey;
+	if (RTA_PAYLOAD(rta) < sizeof(*param))
+		goto badkey;
+
+	param = RTA_DATA(rta);
+	enckeylen = be32_to_cpu(param->enckeylen);
+
+	key += RTA_ALIGN(rta->rta_len);
+	keylen -= RTA_ALIGN(rta->rta_len);
+
+	if (keylen < enckeylen)
+		goto badkey;
+
 	authkeylen = keylen - enckeylen;
 	authkeylen = keylen - enckeylen;
 
 
 	crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
 	crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
@@ -71,21 +82,38 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 
 
 out:
 out:
 	return err;
 	return err;
+
+badkey:
+	crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
+	goto out;
 }
 }
 
 
-static int crypto_authenc_hash(struct aead_request *req)
+static void authenc_chain(struct scatterlist *head, struct scatterlist *sg,
+			  int chain)
+{
+	if (chain) {
+		head->length += sg->length;
+		sg = scatterwalk_sg_next(sg);
+	}
+
+	if (sg)
+		scatterwalk_sg_chain(head, 2, sg);
+	else
+		sg_mark_end(head);
+}
+
+static u8 *crypto_authenc_hash(struct aead_request *req, unsigned int flags,
+			       struct scatterlist *cipher,
+			       unsigned int cryptlen)
 {
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
-	struct authenc_instance_ctx *ictx =
-		crypto_instance_ctx(crypto_aead_alg_instance(authenc));
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_hash *auth = ctx->auth;
 	struct crypto_hash *auth = ctx->auth;
 	struct hash_desc desc = {
 	struct hash_desc desc = {
 		.tfm = auth,
 		.tfm = auth,
+		.flags = aead_request_flags(req) & flags,
 	};
 	};
 	u8 *hash = aead_request_ctx(req);
 	u8 *hash = aead_request_ctx(req);
-	struct scatterlist *dst = req->dst;
-	unsigned int cryptlen = req->cryptlen;
 	int err;
 	int err;
 
 
 	hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), 
 	hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), 
@@ -100,7 +128,7 @@ static int crypto_authenc_hash(struct aead_request *req)
 	if (err)
 	if (err)
 		goto auth_unlock;
 		goto auth_unlock;
 
 
-	err = crypto_hash_update(&desc, dst, cryptlen);
+	err = crypto_hash_update(&desc, cipher, cryptlen);
 	if (err)
 	if (err)
 		goto auth_unlock;
 		goto auth_unlock;
 
 
@@ -109,17 +137,53 @@ auth_unlock:
 	spin_unlock_bh(&ctx->auth_lock);
 	spin_unlock_bh(&ctx->auth_lock);
 
 
 	if (err)
 	if (err)
-		return err;
+		return ERR_PTR(err);
+
+	return hash;
+}
 
 
-	scatterwalk_map_and_copy(hash, dst, cryptlen, ictx->authsize, 1);
+static int crypto_authenc_genicv(struct aead_request *req, u8 *iv,
+				 unsigned int flags)
+{
+	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct scatterlist *dst = req->dst;
+	struct scatterlist cipher[2];
+	struct page *dstp;
+	unsigned int ivsize = crypto_aead_ivsize(authenc);
+	unsigned int cryptlen;
+	u8 *vdst;
+	u8 *hash;
+
+	dstp = sg_page(dst);
+	vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset;
+
+	sg_init_table(cipher, 2);
+	sg_set_buf(cipher, iv, ivsize);
+	authenc_chain(cipher, dst, vdst == iv + ivsize);
+
+	cryptlen = req->cryptlen + ivsize;
+	hash = crypto_authenc_hash(req, flags, cipher, cryptlen);
+	if (IS_ERR(hash))
+		return PTR_ERR(hash);
+
+	scatterwalk_map_and_copy(hash, cipher, cryptlen,
+				 crypto_aead_authsize(authenc), 1);
 	return 0;
 	return 0;
 }
 }
 
 
 static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
 static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
 					int err)
 					int err)
 {
 {
-	if (!err)
-		err = crypto_authenc_hash(req->data);
+	if (!err) {
+		struct aead_request *areq = req->data;
+		struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+		struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
+		struct ablkcipher_request *abreq = aead_request_ctx(areq);
+		u8 *iv = (u8 *)(abreq + 1) +
+			 crypto_ablkcipher_reqsize(ctx->enc);
+
+		err = crypto_authenc_genicv(areq, iv, 0);
+	}
 
 
 	aead_request_complete(req->data, err);
 	aead_request_complete(req->data, err);
 }
 }
@@ -129,72 +193,99 @@ static int crypto_authenc_encrypt(struct aead_request *req)
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct ablkcipher_request *abreq = aead_request_ctx(req);
 	struct ablkcipher_request *abreq = aead_request_ctx(req);
+	struct crypto_ablkcipher *enc = ctx->enc;
+	struct scatterlist *dst = req->dst;
+	unsigned int cryptlen = req->cryptlen;
+	u8 *iv = (u8 *)(abreq + 1) + crypto_ablkcipher_reqsize(enc);
 	int err;
 	int err;
 
 
-	ablkcipher_request_set_tfm(abreq, ctx->enc);
+	ablkcipher_request_set_tfm(abreq, enc);
 	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
 	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
 					crypto_authenc_encrypt_done, req);
 					crypto_authenc_encrypt_done, req);
-	ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen,
-				     req->iv);
+	ablkcipher_request_set_crypt(abreq, req->src, dst, cryptlen, req->iv);
+
+	memcpy(iv, req->iv, crypto_aead_ivsize(authenc));
 
 
 	err = crypto_ablkcipher_encrypt(abreq);
 	err = crypto_ablkcipher_encrypt(abreq);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
-	return crypto_authenc_hash(req);
+	return crypto_authenc_genicv(req, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
 }
 }
 
 
-static int crypto_authenc_verify(struct aead_request *req)
+static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
+					   int err)
 {
 {
-	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
-	struct authenc_instance_ctx *ictx =
-		crypto_instance_ctx(crypto_aead_alg_instance(authenc));
+	if (!err) {
+		struct aead_givcrypt_request *greq = req->data;
+
+		err = crypto_authenc_genicv(&greq->areq, greq->giv, 0);
+	}
+
+	aead_request_complete(req->data, err);
+}
+
+static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req)
+{
+	struct crypto_aead *authenc = aead_givcrypt_reqtfm(req);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
-	struct crypto_hash *auth = ctx->auth;
-	struct hash_desc desc = {
-		.tfm = auth,
-		.flags = aead_request_flags(req),
-	};
-	u8 *ohash = aead_request_ctx(req);
-	u8 *ihash;
-	struct scatterlist *src = req->src;
-	unsigned int cryptlen = req->cryptlen;
-	unsigned int authsize;
+	struct aead_request *areq = &req->areq;
+	struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
+	u8 *iv = req->giv;
 	int err;
 	int err;
 
 
-	ohash = (u8 *)ALIGN((unsigned long)ohash + crypto_hash_alignmask(auth), 
-			    crypto_hash_alignmask(auth) + 1);
-	ihash = ohash + crypto_hash_digestsize(auth);
-
-	spin_lock_bh(&ctx->auth_lock);
-	err = crypto_hash_init(&desc);
-	if (err)
-		goto auth_unlock;
+	skcipher_givcrypt_set_tfm(greq, ctx->enc);
+	skcipher_givcrypt_set_callback(greq, aead_request_flags(areq),
+				       crypto_authenc_givencrypt_done, areq);
+	skcipher_givcrypt_set_crypt(greq, areq->src, areq->dst, areq->cryptlen,
+				    areq->iv);
+	skcipher_givcrypt_set_giv(greq, iv, req->seq);
 
 
-	err = crypto_hash_update(&desc, req->assoc, req->assoclen);
+	err = crypto_skcipher_givencrypt(greq);
 	if (err)
 	if (err)
-		goto auth_unlock;
+		return err;
 
 
-	err = crypto_hash_update(&desc, src, cryptlen);
-	if (err)
-		goto auth_unlock;
+	return crypto_authenc_genicv(areq, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
+}
 
 
-	err = crypto_hash_final(&desc, ohash);
-auth_unlock:
-	spin_unlock_bh(&ctx->auth_lock);
+static int crypto_authenc_verify(struct aead_request *req,
+				 struct scatterlist *cipher,
+				 unsigned int cryptlen)
+{
+	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	u8 *ohash;
+	u8 *ihash;
+	unsigned int authsize;
 
 
-	if (err)
-		return err;
+	ohash = crypto_authenc_hash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher,
+				    cryptlen);
+	if (IS_ERR(ohash))
+		return PTR_ERR(ohash);
 
 
-	authsize = ictx->authsize;
-	scatterwalk_map_and_copy(ihash, src, cryptlen, authsize, 0);
-	return memcmp(ihash, ohash, authsize) ? -EINVAL : 0;
+	authsize = crypto_aead_authsize(authenc);
+	ihash = ohash + authsize;
+	scatterwalk_map_and_copy(ihash, cipher, cryptlen, authsize, 0);
+	return memcmp(ihash, ohash, authsize) ? -EBADMSG: 0;
 }
 }
 
 
-static void crypto_authenc_decrypt_done(struct crypto_async_request *req,
-					int err)
+static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
+				  unsigned int cryptlen)
 {
 {
-	aead_request_complete(req->data, err);
+	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct scatterlist *src = req->src;
+	struct scatterlist cipher[2];
+	struct page *srcp;
+	unsigned int ivsize = crypto_aead_ivsize(authenc);
+	u8 *vsrc;
+
+	srcp = sg_page(src);
+	vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset;
+
+	sg_init_table(cipher, 2);
+	sg_set_buf(cipher, iv, ivsize);
+	authenc_chain(cipher, src, vsrc == iv + ivsize);
+
+	return crypto_authenc_verify(req, cipher, cryptlen + ivsize);
 }
 }
 
 
 static int crypto_authenc_decrypt(struct aead_request *req)
 static int crypto_authenc_decrypt(struct aead_request *req)
@@ -202,17 +293,23 @@ static int crypto_authenc_decrypt(struct aead_request *req)
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 	struct ablkcipher_request *abreq = aead_request_ctx(req);
 	struct ablkcipher_request *abreq = aead_request_ctx(req);
+	unsigned int cryptlen = req->cryptlen;
+	unsigned int authsize = crypto_aead_authsize(authenc);
+	u8 *iv = req->iv;
 	int err;
 	int err;
 
 
-	err = crypto_authenc_verify(req);
+	if (cryptlen < authsize)
+		return -EINVAL;
+	cryptlen -= authsize;
+
+	err = crypto_authenc_iverify(req, iv, cryptlen);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
 	ablkcipher_request_set_tfm(abreq, ctx->enc);
 	ablkcipher_request_set_tfm(abreq, ctx->enc);
 	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
 	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
-					crypto_authenc_decrypt_done, req);
-	ablkcipher_request_set_crypt(abreq, req->src, req->dst, req->cryptlen,
-				     req->iv);
+					req->base.complete, req->base.data);
+	ablkcipher_request_set_crypt(abreq, req->src, req->dst, cryptlen, iv);
 
 
 	return crypto_ablkcipher_decrypt(abreq);
 	return crypto_ablkcipher_decrypt(abreq);
 }
 }
@@ -224,19 +321,13 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
 	struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypto_hash *auth;
 	struct crypto_hash *auth;
 	struct crypto_ablkcipher *enc;
 	struct crypto_ablkcipher *enc;
-	unsigned int digestsize;
 	int err;
 	int err;
 
 
 	auth = crypto_spawn_hash(&ictx->auth);
 	auth = crypto_spawn_hash(&ictx->auth);
 	if (IS_ERR(auth))
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 		return PTR_ERR(auth);
 
 
-	err = -EINVAL;
-	digestsize = crypto_hash_digestsize(auth);
-	if (ictx->authsize > digestsize)
-		goto err_free_hash;
-
-	enc = crypto_spawn_ablkcipher(&ictx->enc);
+	enc = crypto_spawn_skcipher(&ictx->enc);
 	err = PTR_ERR(enc);
 	err = PTR_ERR(enc);
 	if (IS_ERR(enc))
 	if (IS_ERR(enc))
 		goto err_free_hash;
 		goto err_free_hash;
@@ -246,9 +337,10 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
 	tfm->crt_aead.reqsize = max_t(unsigned int,
 	tfm->crt_aead.reqsize = max_t(unsigned int,
 				      (crypto_hash_alignmask(auth) &
 				      (crypto_hash_alignmask(auth) &
 				       ~(crypto_tfm_ctx_alignment() - 1)) +
 				       ~(crypto_tfm_ctx_alignment() - 1)) +
-				      digestsize * 2,
-				      sizeof(struct ablkcipher_request) +
-				      crypto_ablkcipher_reqsize(enc));
+				      crypto_hash_digestsize(auth) * 2,
+				      sizeof(struct skcipher_givcrypt_request) +
+				      crypto_ablkcipher_reqsize(enc) +
+				      crypto_ablkcipher_ivsize(enc));
 
 
 	spin_lock_init(&ctx->auth_lock);
 	spin_lock_init(&ctx->auth_lock);
 
 
@@ -269,75 +361,74 @@ static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm)
 
 
 static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 {
 {
+	struct crypto_attr_type *algt;
 	struct crypto_instance *inst;
 	struct crypto_instance *inst;
 	struct crypto_alg *auth;
 	struct crypto_alg *auth;
 	struct crypto_alg *enc;
 	struct crypto_alg *enc;
 	struct authenc_instance_ctx *ctx;
 	struct authenc_instance_ctx *ctx;
-	unsigned int authsize;
-	unsigned int enckeylen;
+	const char *enc_name;
 	int err;
 	int err;
 
 
-	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD);
-	if (err)
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
 		return ERR_PTR(err);
 		return ERR_PTR(err);
 
 
+	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+		return ERR_PTR(-EINVAL);
+
 	auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
 	auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
 			       CRYPTO_ALG_TYPE_HASH_MASK);
 			       CRYPTO_ALG_TYPE_HASH_MASK);
 	if (IS_ERR(auth))
 	if (IS_ERR(auth))
 		return ERR_PTR(PTR_ERR(auth));
 		return ERR_PTR(PTR_ERR(auth));
 
 
-	err = crypto_attr_u32(tb[2], &authsize);
-	inst = ERR_PTR(err);
-	if (err)
-		goto out_put_auth;
-
-	enc = crypto_attr_alg(tb[3], CRYPTO_ALG_TYPE_BLKCIPHER,
-			      CRYPTO_ALG_TYPE_MASK);
-	inst = ERR_PTR(PTR_ERR(enc));
-	if (IS_ERR(enc))
+	enc_name = crypto_attr_alg_name(tb[2]);
+	err = PTR_ERR(enc_name);
+	if (IS_ERR(enc_name))
 		goto out_put_auth;
 		goto out_put_auth;
 
 
-	err = crypto_attr_u32(tb[4], &enckeylen);
-	if (err)
-		goto out_put_enc;
-
 	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
 	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
 	err = -ENOMEM;
 	err = -ENOMEM;
 	if (!inst)
 	if (!inst)
-		goto out_put_enc;
-
-	err = -ENAMETOOLONG;
-	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
-		     "authenc(%s,%u,%s,%u)", auth->cra_name, authsize,
-		     enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME)
-		goto err_free_inst;
-
-	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
-		     "authenc(%s,%u,%s,%u)", auth->cra_driver_name,
-		     authsize, enc->cra_driver_name, enckeylen) >=
-	    CRYPTO_MAX_ALG_NAME)
-		goto err_free_inst;
+		goto out_put_auth;
 
 
 	ctx = crypto_instance_ctx(inst);
 	ctx = crypto_instance_ctx(inst);
-	ctx->authsize = authsize;
-	ctx->enckeylen = enckeylen;
 
 
 	err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK);
 	err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK);
 	if (err)
 	if (err)
 		goto err_free_inst;
 		goto err_free_inst;
 
 
-	err = crypto_init_spawn(&ctx->enc, enc, inst, CRYPTO_ALG_TYPE_MASK);
+	crypto_set_skcipher_spawn(&ctx->enc, inst);
+	err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
+				   crypto_requires_sync(algt->type,
+							algt->mask));
 	if (err)
 	if (err)
 		goto err_drop_auth;
 		goto err_drop_auth;
 
 
-	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
+	enc = crypto_skcipher_spawn_alg(&ctx->enc);
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+		     "authenc(%s,%s)", auth->cra_name, enc->cra_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		goto err_drop_enc;
+
+	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "authenc(%s,%s)", auth->cra_driver_name,
+		     enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+		goto err_drop_enc;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+	inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC;
 	inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority;
 	inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority;
 	inst->alg.cra_blocksize = enc->cra_blocksize;
 	inst->alg.cra_blocksize = enc->cra_blocksize;
-	inst->alg.cra_alignmask = max(auth->cra_alignmask, enc->cra_alignmask);
+	inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask;
 	inst->alg.cra_type = &crypto_aead_type;
 	inst->alg.cra_type = &crypto_aead_type;
 
 
-	inst->alg.cra_aead.ivsize = enc->cra_blkcipher.ivsize;
-	inst->alg.cra_aead.authsize = authsize;
+	inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
+	inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ?
+					 auth->cra_hash.digestsize :
+					 auth->cra_digest.dia_digestsize;
 
 
 	inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
 	inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
 
 
@@ -347,18 +438,19 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 	inst->alg.cra_aead.setkey = crypto_authenc_setkey;
 	inst->alg.cra_aead.setkey = crypto_authenc_setkey;
 	inst->alg.cra_aead.encrypt = crypto_authenc_encrypt;
 	inst->alg.cra_aead.encrypt = crypto_authenc_encrypt;
 	inst->alg.cra_aead.decrypt = crypto_authenc_decrypt;
 	inst->alg.cra_aead.decrypt = crypto_authenc_decrypt;
+	inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt;
 
 
 out:
 out:
-	crypto_mod_put(enc);
-out_put_auth:
 	crypto_mod_put(auth);
 	crypto_mod_put(auth);
 	return inst;
 	return inst;
 
 
+err_drop_enc:
+	crypto_drop_skcipher(&ctx->enc);
 err_drop_auth:
 err_drop_auth:
 	crypto_drop_spawn(&ctx->auth);
 	crypto_drop_spawn(&ctx->auth);
 err_free_inst:
 err_free_inst:
 	kfree(inst);
 	kfree(inst);
-out_put_enc:
+out_put_auth:
 	inst = ERR_PTR(err);
 	inst = ERR_PTR(err);
 	goto out;
 	goto out;
 }
 }
@@ -367,7 +459,7 @@ static void crypto_authenc_free(struct crypto_instance *inst)
 {
 {
 	struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst);
 	struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst);
 
 
-	crypto_drop_spawn(&ctx->enc);
+	crypto_drop_skcipher(&ctx->enc);
 	crypto_drop_spawn(&ctx->auth);
 	crypto_drop_spawn(&ctx->auth);
 	kfree(inst);
 	kfree(inst);
 }
 }

+ 194 - 8
crypto/blkcipher.c

@@ -14,7 +14,8 @@
  *
  *
  */
  */
 
 
-#include <linux/crypto.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/hardirq.h>
 #include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -25,7 +26,6 @@
 #include <linux/string.h>
 #include <linux/string.h>
 
 
 #include "internal.h"
 #include "internal.h"
-#include "scatterwalk.h"
 
 
 enum {
 enum {
 	BLKCIPHER_WALK_PHYS = 1 << 0,
 	BLKCIPHER_WALK_PHYS = 1 << 0,
@@ -433,9 +433,8 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
 	struct blkcipher_alg *cipher = &alg->cra_blkcipher;
 	struct blkcipher_alg *cipher = &alg->cra_blkcipher;
 	unsigned int len = alg->cra_ctxsize;
 	unsigned int len = alg->cra_ctxsize;
 
 
-	type ^= CRYPTO_ALG_ASYNC;
-	mask &= CRYPTO_ALG_ASYNC;
-	if ((type & mask) && cipher->ivsize) {
+	if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK &&
+	    cipher->ivsize) {
 		len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
 		len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
 		len += cipher->ivsize;
 		len += cipher->ivsize;
 	}
 	}
@@ -451,6 +450,11 @@ static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm)
 	crt->setkey = async_setkey;
 	crt->setkey = async_setkey;
 	crt->encrypt = async_encrypt;
 	crt->encrypt = async_encrypt;
 	crt->decrypt = async_decrypt;
 	crt->decrypt = async_decrypt;
+	if (!alg->ivsize) {
+		crt->givencrypt = skcipher_null_givencrypt;
+		crt->givdecrypt = skcipher_null_givdecrypt;
+	}
+	crt->base = __crypto_ablkcipher_cast(tfm);
 	crt->ivsize = alg->ivsize;
 	crt->ivsize = alg->ivsize;
 
 
 	return 0;
 	return 0;
@@ -482,9 +486,7 @@ static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
 	if (alg->ivsize > PAGE_SIZE / 8)
 	if (alg->ivsize > PAGE_SIZE / 8)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	type ^= CRYPTO_ALG_ASYNC;
-	mask &= CRYPTO_ALG_ASYNC;
-	if (type & mask)
+	if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK)
 		return crypto_init_blkcipher_ops_sync(tfm);
 		return crypto_init_blkcipher_ops_sync(tfm);
 	else
 	else
 		return crypto_init_blkcipher_ops_async(tfm);
 		return crypto_init_blkcipher_ops_async(tfm);
@@ -499,6 +501,8 @@ static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
 	seq_printf(m, "min keysize  : %u\n", alg->cra_blkcipher.min_keysize);
 	seq_printf(m, "min keysize  : %u\n", alg->cra_blkcipher.min_keysize);
 	seq_printf(m, "max keysize  : %u\n", alg->cra_blkcipher.max_keysize);
 	seq_printf(m, "max keysize  : %u\n", alg->cra_blkcipher.max_keysize);
 	seq_printf(m, "ivsize       : %u\n", alg->cra_blkcipher.ivsize);
 	seq_printf(m, "ivsize       : %u\n", alg->cra_blkcipher.ivsize);
+	seq_printf(m, "geniv        : %s\n", alg->cra_blkcipher.geniv ?:
+					     "<default>");
 }
 }
 
 
 const struct crypto_type crypto_blkcipher_type = {
 const struct crypto_type crypto_blkcipher_type = {
@@ -510,5 +514,187 @@ const struct crypto_type crypto_blkcipher_type = {
 };
 };
 EXPORT_SYMBOL_GPL(crypto_blkcipher_type);
 EXPORT_SYMBOL_GPL(crypto_blkcipher_type);
 
 
+static int crypto_grab_nivcipher(struct crypto_skcipher_spawn *spawn,
+				const char *name, u32 type, u32 mask)
+{
+	struct crypto_alg *alg;
+	int err;
+
+	type = crypto_skcipher_type(type);
+	mask = crypto_skcipher_mask(mask) | CRYPTO_ALG_GENIV;
+
+	alg = crypto_alg_mod_lookup(name, type, mask);
+	if (IS_ERR(alg))
+		return PTR_ERR(alg);
+
+	err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
+	crypto_mod_put(alg);
+	return err;
+}
+
+struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl,
+					     struct rtattr **tb, u32 type,
+					     u32 mask)
+{
+	struct {
+		int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+			      unsigned int keylen);
+		int (*encrypt)(struct ablkcipher_request *req);
+		int (*decrypt)(struct ablkcipher_request *req);
+
+		unsigned int min_keysize;
+		unsigned int max_keysize;
+		unsigned int ivsize;
+
+		const char *geniv;
+	} balg;
+	const char *name;
+	struct crypto_skcipher_spawn *spawn;
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ (CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV)) &
+	    algt->mask)
+		return ERR_PTR(-EINVAL);
+
+	name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(name);
+	if (IS_ERR(name))
+		return ERR_PTR(err);
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+	if (!inst)
+		return ERR_PTR(-ENOMEM);
+
+	spawn = crypto_instance_ctx(inst);
+
+	/* Ignore async algorithms if necessary. */
+	mask |= crypto_requires_sync(algt->type, algt->mask);
+
+	crypto_set_skcipher_spawn(spawn, inst);
+	err = crypto_grab_nivcipher(spawn, name, type, mask);
+	if (err)
+		goto err_free_inst;
+
+	alg = crypto_skcipher_spawn_alg(spawn);
+
+	if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+	    CRYPTO_ALG_TYPE_BLKCIPHER) {
+		balg.ivsize = alg->cra_blkcipher.ivsize;
+		balg.min_keysize = alg->cra_blkcipher.min_keysize;
+		balg.max_keysize = alg->cra_blkcipher.max_keysize;
+
+		balg.setkey = async_setkey;
+		balg.encrypt = async_encrypt;
+		balg.decrypt = async_decrypt;
+
+		balg.geniv = alg->cra_blkcipher.geniv;
+	} else {
+		balg.ivsize = alg->cra_ablkcipher.ivsize;
+		balg.min_keysize = alg->cra_ablkcipher.min_keysize;
+		balg.max_keysize = alg->cra_ablkcipher.max_keysize;
+
+		balg.setkey = alg->cra_ablkcipher.setkey;
+		balg.encrypt = alg->cra_ablkcipher.encrypt;
+		balg.decrypt = alg->cra_ablkcipher.decrypt;
+
+		balg.geniv = alg->cra_ablkcipher.geniv;
+	}
+
+	err = -EINVAL;
+	if (!balg.ivsize)
+		goto err_drop_alg;
+
+	/*
+	 * This is only true if we're constructing an algorithm with its
+	 * default IV generator.  For the default generator we elide the
+	 * template name and double-check the IV generator.
+	 */
+	if (algt->mask & CRYPTO_ALG_GENIV) {
+		if (!balg.geniv)
+			balg.geniv = crypto_default_geniv(alg);
+		err = -EAGAIN;
+		if (strcmp(tmpl->name, balg.geniv))
+			goto err_drop_alg;
+
+		memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+		memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
+		       CRYPTO_MAX_ALG_NAME);
+	} else {
+		err = -ENAMETOOLONG;
+		if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+			     "%s(%s)", tmpl->name, alg->cra_name) >=
+		    CRYPTO_MAX_ALG_NAME)
+			goto err_drop_alg;
+		if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+			     "%s(%s)", tmpl->name, alg->cra_driver_name) >=
+		    CRYPTO_MAX_ALG_NAME)
+			goto err_drop_alg;
+	}
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV;
+	inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = alg->cra_blocksize;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_givcipher_type;
+
+	inst->alg.cra_ablkcipher.ivsize = balg.ivsize;
+	inst->alg.cra_ablkcipher.min_keysize = balg.min_keysize;
+	inst->alg.cra_ablkcipher.max_keysize = balg.max_keysize;
+	inst->alg.cra_ablkcipher.geniv = balg.geniv;
+
+	inst->alg.cra_ablkcipher.setkey = balg.setkey;
+	inst->alg.cra_ablkcipher.encrypt = balg.encrypt;
+	inst->alg.cra_ablkcipher.decrypt = balg.decrypt;
+
+out:
+	return inst;
+
+err_drop_alg:
+	crypto_drop_skcipher(spawn);
+err_free_inst:
+	kfree(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_alloc);
+
+void skcipher_geniv_free(struct crypto_instance *inst)
+{
+	crypto_drop_skcipher(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_free);
+
+int skcipher_geniv_init(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_ablkcipher *cipher;
+
+	cipher = crypto_spawn_skcipher(crypto_instance_ctx(inst));
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	tfm->crt_ablkcipher.base = cipher;
+	tfm->crt_ablkcipher.reqsize += crypto_ablkcipher_reqsize(cipher);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_init);
+
+void skcipher_geniv_exit(struct crypto_tfm *tfm)
+{
+	crypto_free_ablkcipher(tfm->crt_ablkcipher.base);
+}
+EXPORT_SYMBOL_GPL(skcipher_geniv_exit);
+
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic block chaining cipher type");
 MODULE_DESCRIPTION("Generic block chaining cipher type");

File diff suppressed because it is too large
+ 394 - 741
crypto/camellia.c


+ 3 - 3
crypto/cast6.c

@@ -369,7 +369,7 @@ static const u8 Tr[4][8] = {
 };
 };
 
 
 /* forward octave */
 /* forward octave */
-static inline void W(u32 *key, unsigned int i) {
+static void W(u32 *key, unsigned int i) {
 	u32 I;
 	u32 I;
 	key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]);
 	key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]);
 	key[5] ^= F2(key[6], Tr[i % 4][1], Tm[i][1]);
 	key[5] ^= F2(key[6], Tr[i % 4][1], Tm[i][1]);
@@ -428,7 +428,7 @@ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
 }
 }
 
 
 /*forward quad round*/
 /*forward quad round*/
-static inline void Q (u32 * block, u8 * Kr, u32 * Km) {
+static void Q (u32 * block, u8 * Kr, u32 * Km) {
 	u32 I;
 	u32 I;
 	block[2] ^= F1(block[3], Kr[0], Km[0]);
 	block[2] ^= F1(block[3], Kr[0], Km[0]);
 	block[1] ^= F2(block[2], Kr[1], Km[1]);
 	block[1] ^= F2(block[2], Kr[1], Km[1]);
@@ -437,7 +437,7 @@ static inline void Q (u32 * block, u8 * Kr, u32 * Km) {
 }
 }
 
 
 /*reverse quad round*/
 /*reverse quad round*/
-static inline void QBAR (u32 * block, u8 * Kr, u32 * Km) {
+static void QBAR (u32 * block, u8 * Kr, u32 * Km) {
 	u32 I;
 	u32 I;
         block[3] ^= F1(block[0], Kr[3], Km[3]);
         block[3] ^= F1(block[0], Kr[3], Km[3]);
         block[0] ^= F3(block[1], Kr[2], Km[2]);
         block[0] ^= F3(block[1], Kr[2], Km[2]);

+ 25 - 84
crypto/cbc.c

@@ -14,13 +14,13 @@
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
 struct crypto_cbc_ctx {
 struct crypto_cbc_ctx {
 	struct crypto_cipher *child;
 	struct crypto_cipher *child;
-	void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
 };
 };
 
 
 static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key,
 static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key,
@@ -41,9 +41,7 @@ static int crypto_cbc_setkey(struct crypto_tfm *parent, const u8 *key,
 
 
 static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
 static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
 				      struct blkcipher_walk *walk,
 				      struct blkcipher_walk *walk,
-				      struct crypto_cipher *tfm,
-				      void (*xor)(u8 *, const u8 *,
-						  unsigned int))
+				      struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_encrypt;
 		crypto_cipher_alg(tfm)->cia_encrypt;
@@ -54,7 +52,7 @@ static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
 	u8 *iv = walk->iv;
 	u8 *iv = walk->iv;
 
 
 	do {
 	do {
-		xor(iv, src, bsize);
+		crypto_xor(iv, src, bsize);
 		fn(crypto_cipher_tfm(tfm), dst, iv);
 		fn(crypto_cipher_tfm(tfm), dst, iv);
 		memcpy(iv, dst, bsize);
 		memcpy(iv, dst, bsize);
 
 
@@ -67,9 +65,7 @@ static int crypto_cbc_encrypt_segment(struct blkcipher_desc *desc,
 
 
 static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc,
 static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc,
 				      struct blkcipher_walk *walk,
 				      struct blkcipher_walk *walk,
-				      struct crypto_cipher *tfm,
-				      void (*xor)(u8 *, const u8 *,
-						  unsigned int))
+				      struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_encrypt;
 		crypto_cipher_alg(tfm)->cia_encrypt;
@@ -79,7 +75,7 @@ static int crypto_cbc_encrypt_inplace(struct blkcipher_desc *desc,
 	u8 *iv = walk->iv;
 	u8 *iv = walk->iv;
 
 
 	do {
 	do {
-		xor(src, iv, bsize);
+		crypto_xor(src, iv, bsize);
 		fn(crypto_cipher_tfm(tfm), src, src);
 		fn(crypto_cipher_tfm(tfm), src, src);
 		iv = src;
 		iv = src;
 
 
@@ -99,7 +95,6 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_cipher *child = ctx->child;
 	struct crypto_cipher *child = ctx->child;
-	void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
 	int err;
 	int err;
 
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -107,11 +102,9 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
 
 
 	while ((nbytes = walk.nbytes)) {
 	while ((nbytes = walk.nbytes)) {
 		if (walk.src.virt.addr == walk.dst.virt.addr)
 		if (walk.src.virt.addr == walk.dst.virt.addr)
-			nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child,
-							    xor);
+			nbytes = crypto_cbc_encrypt_inplace(desc, &walk, child);
 		else
 		else
-			nbytes = crypto_cbc_encrypt_segment(desc, &walk, child,
-							    xor);
+			nbytes = crypto_cbc_encrypt_segment(desc, &walk, child);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 	}
 
 
@@ -120,9 +113,7 @@ static int crypto_cbc_encrypt(struct blkcipher_desc *desc,
 
 
 static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
 static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
 				      struct blkcipher_walk *walk,
 				      struct blkcipher_walk *walk,
-				      struct crypto_cipher *tfm,
-				      void (*xor)(u8 *, const u8 *,
-						  unsigned int))
+				      struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_decrypt;
 		crypto_cipher_alg(tfm)->cia_decrypt;
@@ -134,7 +125,7 @@ static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
 
 
 	do {
 	do {
 		fn(crypto_cipher_tfm(tfm), dst, src);
 		fn(crypto_cipher_tfm(tfm), dst, src);
-		xor(dst, iv, bsize);
+		crypto_xor(dst, iv, bsize);
 		iv = src;
 		iv = src;
 
 
 		src += bsize;
 		src += bsize;
@@ -148,34 +139,29 @@ static int crypto_cbc_decrypt_segment(struct blkcipher_desc *desc,
 
 
 static int crypto_cbc_decrypt_inplace(struct blkcipher_desc *desc,
 static int crypto_cbc_decrypt_inplace(struct blkcipher_desc *desc,
 				      struct blkcipher_walk *walk,
 				      struct blkcipher_walk *walk,
-				      struct crypto_cipher *tfm,
-				      void (*xor)(u8 *, const u8 *,
-						  unsigned int))
+				      struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_decrypt;
 		crypto_cipher_alg(tfm)->cia_decrypt;
 	int bsize = crypto_cipher_blocksize(tfm);
 	int bsize = crypto_cipher_blocksize(tfm);
-	unsigned long alignmask = crypto_cipher_alignmask(tfm);
 	unsigned int nbytes = walk->nbytes;
 	unsigned int nbytes = walk->nbytes;
 	u8 *src = walk->src.virt.addr;
 	u8 *src = walk->src.virt.addr;
-	u8 stack[bsize + alignmask];
-	u8 *first_iv = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
-
-	memcpy(first_iv, walk->iv, bsize);
+	u8 last_iv[bsize];
 
 
 	/* Start of the last block. */
 	/* Start of the last block. */
-	src += nbytes - nbytes % bsize - bsize;
-	memcpy(walk->iv, src, bsize);
+	src += nbytes - (nbytes & (bsize - 1)) - bsize;
+	memcpy(last_iv, src, bsize);
 
 
 	for (;;) {
 	for (;;) {
 		fn(crypto_cipher_tfm(tfm), src, src);
 		fn(crypto_cipher_tfm(tfm), src, src);
 		if ((nbytes -= bsize) < bsize)
 		if ((nbytes -= bsize) < bsize)
 			break;
 			break;
-		xor(src, src - bsize, bsize);
+		crypto_xor(src, src - bsize, bsize);
 		src -= bsize;
 		src -= bsize;
 	}
 	}
 
 
-	xor(src, first_iv, bsize);
+	crypto_xor(src, walk->iv, bsize);
+	memcpy(walk->iv, last_iv, bsize);
 
 
 	return nbytes;
 	return nbytes;
 }
 }
@@ -188,7 +174,6 @@ static int crypto_cbc_decrypt(struct blkcipher_desc *desc,
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_cbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_cipher *child = ctx->child;
 	struct crypto_cipher *child = ctx->child;
-	void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
 	int err;
 	int err;
 
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -196,48 +181,15 @@ static int crypto_cbc_decrypt(struct blkcipher_desc *desc,
 
 
 	while ((nbytes = walk.nbytes)) {
 	while ((nbytes = walk.nbytes)) {
 		if (walk.src.virt.addr == walk.dst.virt.addr)
 		if (walk.src.virt.addr == walk.dst.virt.addr)
-			nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child,
-							    xor);
+			nbytes = crypto_cbc_decrypt_inplace(desc, &walk, child);
 		else
 		else
-			nbytes = crypto_cbc_decrypt_segment(desc, &walk, child,
-							    xor);
+			nbytes = crypto_cbc_decrypt_segment(desc, &walk, child);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 	}
 
 
 	return err;
 	return err;
 }
 }
 
 
-static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
-{
-	do {
-		*a++ ^= *b++;
-	} while (--bs);
-}
-
-static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
-{
-	u32 *a = (u32 *)dst;
-	u32 *b = (u32 *)src;
-
-	do {
-		*a++ ^= *b++;
-	} while ((bs -= 4));
-}
-
-static void xor_64(u8 *a, const u8 *b, unsigned int bs)
-{
-	((u32 *)a)[0] ^= ((u32 *)b)[0];
-	((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static void xor_128(u8 *a, const u8 *b, unsigned int bs)
-{
-	((u32 *)a)[0] ^= ((u32 *)b)[0];
-	((u32 *)a)[1] ^= ((u32 *)b)[1];
-	((u32 *)a)[2] ^= ((u32 *)b)[2];
-	((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
 static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
 static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
 {
 {
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
@@ -245,22 +197,6 @@ static int crypto_cbc_init_tfm(struct crypto_tfm *tfm)
 	struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypto_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypto_cipher *cipher;
 	struct crypto_cipher *cipher;
 
 
-	switch (crypto_tfm_alg_blocksize(tfm)) {
-	case 8:
-		ctx->xor = xor_64;
-		break;
-
-	case 16:
-		ctx->xor = xor_128;
-		break;
-
-	default:
-		if (crypto_tfm_alg_blocksize(tfm) % 4)
-			ctx->xor = xor_byte;
-		else
-			ctx->xor = xor_quad;
-	}
-
 	cipher = crypto_spawn_cipher(spawn);
 	cipher = crypto_spawn_cipher(spawn);
 	if (IS_ERR(cipher))
 	if (IS_ERR(cipher))
 		return PTR_ERR(cipher);
 		return PTR_ERR(cipher);
@@ -290,6 +226,10 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
 	if (IS_ERR(alg))
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 		return ERR_PTR(PTR_ERR(alg));
 
 
+	inst = ERR_PTR(-EINVAL);
+	if (!is_power_of_2(alg->cra_blocksize))
+		goto out_put_alg;
+
 	inst = crypto_alloc_instance("cbc", alg);
 	inst = crypto_alloc_instance("cbc", alg);
 	if (IS_ERR(inst))
 	if (IS_ERR(inst))
 		goto out_put_alg;
 		goto out_put_alg;
@@ -300,8 +240,9 @@ static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
 	inst->alg.cra_alignmask = alg->cra_alignmask;
 	inst->alg.cra_alignmask = alg->cra_alignmask;
 	inst->alg.cra_type = &crypto_blkcipher_type;
 	inst->alg.cra_type = &crypto_blkcipher_type;
 
 
-	if (!(alg->cra_blocksize % 4))
-		inst->alg.cra_alignmask |= 3;
+	/* We access the data as u32s when xoring. */
+	inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+
 	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
 	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
 	inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
 	inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
 	inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
 	inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;

+ 889 - 0
crypto/ccm.c

@@ -0,0 +1,889 @@
+/*
+ * CCM: Counter with CBC-MAC
+ *
+ * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * 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 <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+struct ccm_instance_ctx {
+	struct crypto_skcipher_spawn ctr;
+	struct crypto_spawn cipher;
+};
+
+struct crypto_ccm_ctx {
+	struct crypto_cipher *cipher;
+	struct crypto_ablkcipher *ctr;
+};
+
+struct crypto_rfc4309_ctx {
+	struct crypto_aead *child;
+	u8 nonce[3];
+};
+
+struct crypto_ccm_req_priv_ctx {
+	u8 odata[16];
+	u8 idata[16];
+	u8 auth_tag[16];
+	u32 ilen;
+	u32 flags;
+	struct scatterlist src[2];
+	struct scatterlist dst[2];
+	struct ablkcipher_request abreq;
+};
+
+static inline struct crypto_ccm_req_priv_ctx *crypto_ccm_reqctx(
+	struct aead_request *req)
+{
+	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
+
+	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
+}
+
+static int set_msg_len(u8 *block, unsigned int msglen, int csize)
+{
+	__be32 data;
+
+	memset(block, 0, csize);
+	block += csize;
+
+	if (csize >= 4)
+		csize = 4;
+	else if (msglen > (1 << (8 * csize)))
+		return -EOVERFLOW;
+
+	data = cpu_to_be32(msglen);
+	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+	return 0;
+}
+
+static int crypto_ccm_setkey(struct crypto_aead *aead, const u8 *key,
+			     unsigned int keylen)
+{
+	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_ablkcipher *ctr = ctx->ctr;
+	struct crypto_cipher *tfm = ctx->cipher;
+	int err = 0;
+
+	crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
+	crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
+				    CRYPTO_TFM_REQ_MASK);
+	err = crypto_ablkcipher_setkey(ctr, key, keylen);
+	crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
+			      CRYPTO_TFM_RES_MASK);
+	if (err)
+		goto out;
+
+	crypto_cipher_clear_flags(tfm, CRYPTO_TFM_REQ_MASK);
+	crypto_cipher_set_flags(tfm, crypto_aead_get_flags(aead) &
+				    CRYPTO_TFM_REQ_MASK);
+	err = crypto_cipher_setkey(tfm, key, keylen);
+	crypto_aead_set_flags(aead, crypto_cipher_get_flags(tfm) &
+			      CRYPTO_TFM_RES_MASK);
+
+out:
+	return err;
+}
+
+static int crypto_ccm_setauthsize(struct crypto_aead *tfm,
+				  unsigned int authsize)
+{
+	switch (authsize) {
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 12:
+	case 14:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int format_input(u8 *info, struct aead_request *req,
+			unsigned int cryptlen)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	unsigned int lp = req->iv[0];
+	unsigned int l = lp + 1;
+	unsigned int m;
+
+	m = crypto_aead_authsize(aead);
+
+	memcpy(info, req->iv, 16);
+
+	/* format control info per RFC 3610 and
+	 * NIST Special Publication 800-38C
+	 */
+	*info |= (8 * ((m - 2) / 2));
+	if (req->assoclen)
+		*info |= 64;
+
+	return set_msg_len(info + 16 - l, cryptlen, l);
+}
+
+static int format_adata(u8 *adata, unsigned int a)
+{
+	int len = 0;
+
+	/* add control info for associated data
+	 * RFC 3610 and NIST Special Publication 800-38C
+	 */
+	if (a < 65280) {
+		*(__be16 *)adata = cpu_to_be16(a);
+		len = 2;
+	} else  {
+		*(__be16 *)adata = cpu_to_be16(0xfffe);
+		*(__be32 *)&adata[2] = cpu_to_be32(a);
+		len = 6;
+	}
+
+	return len;
+}
+
+static void compute_mac(struct crypto_cipher *tfm, u8 *data, int n,
+		       struct crypto_ccm_req_priv_ctx *pctx)
+{
+	unsigned int bs = 16;
+	u8 *odata = pctx->odata;
+	u8 *idata = pctx->idata;
+	int datalen, getlen;
+
+	datalen = n;
+
+	/* first time in here, block may be partially filled. */
+	getlen = bs - pctx->ilen;
+	if (datalen >= getlen) {
+		memcpy(idata + pctx->ilen, data, getlen);
+		crypto_xor(odata, idata, bs);
+		crypto_cipher_encrypt_one(tfm, odata, odata);
+		datalen -= getlen;
+		data += getlen;
+		pctx->ilen = 0;
+	}
+
+	/* now encrypt rest of data */
+	while (datalen >= bs) {
+		crypto_xor(odata, data, bs);
+		crypto_cipher_encrypt_one(tfm, odata, odata);
+
+		datalen -= bs;
+		data += bs;
+	}
+
+	/* check and see if there's leftover data that wasn't
+	 * enough to fill a block.
+	 */
+	if (datalen) {
+		memcpy(idata + pctx->ilen, data, datalen);
+		pctx->ilen += datalen;
+	}
+}
+
+static void get_data_to_compute(struct crypto_cipher *tfm,
+			       struct crypto_ccm_req_priv_ctx *pctx,
+			       struct scatterlist *sg, unsigned int len)
+{
+	struct scatter_walk walk;
+	u8 *data_src;
+	int n;
+
+	scatterwalk_start(&walk, sg);
+
+	while (len) {
+		n = scatterwalk_clamp(&walk, len);
+		if (!n) {
+			scatterwalk_start(&walk, sg_next(walk.sg));
+			n = scatterwalk_clamp(&walk, len);
+		}
+		data_src = scatterwalk_map(&walk, 0);
+
+		compute_mac(tfm, data_src, n, pctx);
+		len -= n;
+
+		scatterwalk_unmap(data_src, 0);
+		scatterwalk_advance(&walk, n);
+		scatterwalk_done(&walk, 0, len);
+		if (len)
+			crypto_yield(pctx->flags);
+	}
+
+	/* any leftover needs padding and then encrypted */
+	if (pctx->ilen) {
+		int padlen;
+		u8 *odata = pctx->odata;
+		u8 *idata = pctx->idata;
+
+		padlen = 16 - pctx->ilen;
+		memset(idata + pctx->ilen, 0, padlen);
+		crypto_xor(odata, idata, 16);
+		crypto_cipher_encrypt_one(tfm, odata, odata);
+		pctx->ilen = 0;
+	}
+}
+
+static int crypto_ccm_auth(struct aead_request *req, struct scatterlist *plain,
+			   unsigned int cryptlen)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+	struct crypto_cipher *cipher = ctx->cipher;
+	unsigned int assoclen = req->assoclen;
+	u8 *odata = pctx->odata;
+	u8 *idata = pctx->idata;
+	int err;
+
+	/* format control data for input */
+	err = format_input(odata, req, cryptlen);
+	if (err)
+		goto out;
+
+	/* encrypt first block to use as start in computing mac  */
+	crypto_cipher_encrypt_one(cipher, odata, odata);
+
+	/* format associated data and compute into mac */
+	if (assoclen) {
+		pctx->ilen = format_adata(idata, assoclen);
+		get_data_to_compute(cipher, pctx, req->assoc, req->assoclen);
+	}
+
+	/* compute plaintext into mac */
+	get_data_to_compute(cipher, pctx, plain, cryptlen);
+
+out:
+	return err;
+}
+
+static void crypto_ccm_encrypt_done(struct crypto_async_request *areq, int err)
+{
+	struct aead_request *req = areq->data;
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+	u8 *odata = pctx->odata;
+
+	if (!err)
+		scatterwalk_map_and_copy(odata, req->dst, req->cryptlen,
+					 crypto_aead_authsize(aead), 1);
+	aead_request_complete(req, err);
+}
+
+static inline int crypto_ccm_check_iv(const u8 *iv)
+{
+	/* 2 <= L <= 8, so 1 <= L' <= 7. */
+	if (1 > iv[0] || iv[0] > 7)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int crypto_ccm_encrypt(struct aead_request *req)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+	struct ablkcipher_request *abreq = &pctx->abreq;
+	struct scatterlist *dst;
+	unsigned int cryptlen = req->cryptlen;
+	u8 *odata = pctx->odata;
+	u8 *iv = req->iv;
+	int err;
+
+	err = crypto_ccm_check_iv(iv);
+	if (err)
+		return err;
+
+	pctx->flags = aead_request_flags(req);
+
+	err = crypto_ccm_auth(req, req->src, cryptlen);
+	if (err)
+		return err;
+
+	 /* Note: rfc 3610 and NIST 800-38C require counter of
+	 * zero to encrypt auth tag.
+	 */
+	memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+	sg_init_table(pctx->src, 2);
+	sg_set_buf(pctx->src, odata, 16);
+	scatterwalk_sg_chain(pctx->src, 2, req->src);
+
+	dst = pctx->src;
+	if (req->src != req->dst) {
+		sg_init_table(pctx->dst, 2);
+		sg_set_buf(pctx->dst, odata, 16);
+		scatterwalk_sg_chain(pctx->dst, 2, req->dst);
+		dst = pctx->dst;
+	}
+
+	ablkcipher_request_set_tfm(abreq, ctx->ctr);
+	ablkcipher_request_set_callback(abreq, pctx->flags,
+					crypto_ccm_encrypt_done, req);
+	ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv);
+	err = crypto_ablkcipher_encrypt(abreq);
+	if (err)
+		return err;
+
+	/* copy authtag to end of dst */
+	scatterwalk_map_and_copy(odata, req->dst, cryptlen,
+				 crypto_aead_authsize(aead), 1);
+	return err;
+}
+
+static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
+				   int err)
+{
+	struct aead_request *req = areq->data;
+	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	unsigned int authsize = crypto_aead_authsize(aead);
+	unsigned int cryptlen = req->cryptlen - authsize;
+
+	if (!err) {
+		err = crypto_ccm_auth(req, req->dst, cryptlen);
+		if (!err && memcmp(pctx->auth_tag, pctx->odata, authsize))
+			err = -EBADMSG;
+	}
+	aead_request_complete(req, err);
+}
+
+static int crypto_ccm_decrypt(struct aead_request *req)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req);
+	struct ablkcipher_request *abreq = &pctx->abreq;
+	struct scatterlist *dst;
+	unsigned int authsize = crypto_aead_authsize(aead);
+	unsigned int cryptlen = req->cryptlen;
+	u8 *authtag = pctx->auth_tag;
+	u8 *odata = pctx->odata;
+	u8 *iv = req->iv;
+	int err;
+
+	if (cryptlen < authsize)
+		return -EINVAL;
+	cryptlen -= authsize;
+
+	err = crypto_ccm_check_iv(iv);
+	if (err)
+		return err;
+
+	pctx->flags = aead_request_flags(req);
+
+	scatterwalk_map_and_copy(authtag, req->src, cryptlen, authsize, 0);
+
+	memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+	sg_init_table(pctx->src, 2);
+	sg_set_buf(pctx->src, authtag, 16);
+	scatterwalk_sg_chain(pctx->src, 2, req->src);
+
+	dst = pctx->src;
+	if (req->src != req->dst) {
+		sg_init_table(pctx->dst, 2);
+		sg_set_buf(pctx->dst, authtag, 16);
+		scatterwalk_sg_chain(pctx->dst, 2, req->dst);
+		dst = pctx->dst;
+	}
+
+	ablkcipher_request_set_tfm(abreq, ctx->ctr);
+	ablkcipher_request_set_callback(abreq, pctx->flags,
+					crypto_ccm_decrypt_done, req);
+	ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv);
+	err = crypto_ablkcipher_decrypt(abreq);
+	if (err)
+		return err;
+
+	err = crypto_ccm_auth(req, req->dst, cryptlen);
+	if (err)
+		return err;
+
+	/* verify */
+	if (memcmp(authtag, odata, authsize))
+		return -EBADMSG;
+
+	return err;
+}
+
+static int crypto_ccm_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct ccm_instance_ctx *ictx = crypto_instance_ctx(inst);
+	struct crypto_ccm_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_cipher *cipher;
+	struct crypto_ablkcipher *ctr;
+	unsigned long align;
+	int err;
+
+	cipher = crypto_spawn_cipher(&ictx->cipher);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctr = crypto_spawn_skcipher(&ictx->ctr);
+	err = PTR_ERR(ctr);
+	if (IS_ERR(ctr))
+		goto err_free_cipher;
+
+	ctx->cipher = cipher;
+	ctx->ctr = ctr;
+
+	align = crypto_tfm_alg_alignmask(tfm);
+	align &= ~(crypto_tfm_ctx_alignment() - 1);
+	tfm->crt_aead.reqsize = align +
+				sizeof(struct crypto_ccm_req_priv_ctx) +
+				crypto_ablkcipher_reqsize(ctr);
+
+	return 0;
+
+err_free_cipher:
+	crypto_free_cipher(cipher);
+	return err;
+}
+
+static void crypto_ccm_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_ccm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_cipher(ctx->cipher);
+	crypto_free_ablkcipher(ctx->ctr);
+}
+
+static struct crypto_instance *crypto_ccm_alloc_common(struct rtattr **tb,
+						       const char *full_name,
+						       const char *ctr_name,
+						       const char *cipher_name)
+{
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	struct crypto_alg *ctr;
+	struct crypto_alg *cipher;
+	struct ccm_instance_ctx *ictx;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+		return ERR_PTR(-EINVAL);
+
+	cipher = crypto_alg_mod_lookup(cipher_name,  CRYPTO_ALG_TYPE_CIPHER,
+				       CRYPTO_ALG_TYPE_MASK);
+	err = PTR_ERR(cipher);
+	if (IS_ERR(cipher))
+		return ERR_PTR(err);
+
+	err = -EINVAL;
+	if (cipher->cra_blocksize != 16)
+		goto out_put_cipher;
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!inst)
+		goto out_put_cipher;
+
+	ictx = crypto_instance_ctx(inst);
+
+	err = crypto_init_spawn(&ictx->cipher, cipher, inst,
+				CRYPTO_ALG_TYPE_MASK);
+	if (err)
+		goto err_free_inst;
+
+	crypto_set_skcipher_spawn(&ictx->ctr, inst);
+	err = crypto_grab_skcipher(&ictx->ctr, ctr_name, 0,
+				   crypto_requires_sync(algt->type,
+							algt->mask));
+	if (err)
+		goto err_drop_cipher;
+
+	ctr = crypto_skcipher_spawn_alg(&ictx->ctr);
+
+	/* Not a stream cipher? */
+	err = -EINVAL;
+	if (ctr->cra_blocksize != 1)
+		goto err_drop_ctr;
+
+	/* We want the real thing! */
+	if (ctr->cra_ablkcipher.ivsize != 16)
+		goto err_drop_ctr;
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "ccm_base(%s,%s)", ctr->cra_driver_name,
+		     cipher->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+		goto err_drop_ctr;
+
+	memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+	inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
+	inst->alg.cra_priority = cipher->cra_priority + ctr->cra_priority;
+	inst->alg.cra_blocksize = 1;
+	inst->alg.cra_alignmask = cipher->cra_alignmask | ctr->cra_alignmask |
+				  (__alignof__(u32) - 1);
+	inst->alg.cra_type = &crypto_aead_type;
+	inst->alg.cra_aead.ivsize = 16;
+	inst->alg.cra_aead.maxauthsize = 16;
+	inst->alg.cra_ctxsize = sizeof(struct crypto_ccm_ctx);
+	inst->alg.cra_init = crypto_ccm_init_tfm;
+	inst->alg.cra_exit = crypto_ccm_exit_tfm;
+	inst->alg.cra_aead.setkey = crypto_ccm_setkey;
+	inst->alg.cra_aead.setauthsize = crypto_ccm_setauthsize;
+	inst->alg.cra_aead.encrypt = crypto_ccm_encrypt;
+	inst->alg.cra_aead.decrypt = crypto_ccm_decrypt;
+
+out:
+	crypto_mod_put(cipher);
+	return inst;
+
+err_drop_ctr:
+	crypto_drop_skcipher(&ictx->ctr);
+err_drop_cipher:
+	crypto_drop_spawn(&ictx->cipher);
+err_free_inst:
+	kfree(inst);
+out_put_cipher:
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static struct crypto_instance *crypto_ccm_alloc(struct rtattr **tb)
+{
+	int err;
+	const char *cipher_name;
+	char ctr_name[CRYPTO_MAX_ALG_NAME];
+	char full_name[CRYPTO_MAX_ALG_NAME];
+
+	cipher_name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(cipher_name);
+	if (IS_ERR(cipher_name))
+		return ERR_PTR(err);
+
+	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
+		     cipher_name) >= CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm(%s)", cipher_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	return crypto_ccm_alloc_common(tb, full_name, ctr_name, cipher_name);
+}
+
+static void crypto_ccm_free(struct crypto_instance *inst)
+{
+	struct ccm_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+	crypto_drop_spawn(&ctx->cipher);
+	crypto_drop_skcipher(&ctx->ctr);
+	kfree(inst);
+}
+
+static struct crypto_template crypto_ccm_tmpl = {
+	.name = "ccm",
+	.alloc = crypto_ccm_alloc,
+	.free = crypto_ccm_free,
+	.module = THIS_MODULE,
+};
+
+static struct crypto_instance *crypto_ccm_base_alloc(struct rtattr **tb)
+{
+	int err;
+	const char *ctr_name;
+	const char *cipher_name;
+	char full_name[CRYPTO_MAX_ALG_NAME];
+
+	ctr_name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(ctr_name);
+	if (IS_ERR(ctr_name))
+		return ERR_PTR(err);
+
+	cipher_name = crypto_attr_alg_name(tb[2]);
+	err = PTR_ERR(cipher_name);
+	if (IS_ERR(cipher_name))
+		return ERR_PTR(err);
+
+	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm_base(%s,%s)",
+		     ctr_name, cipher_name) >= CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	return crypto_ccm_alloc_common(tb, full_name, ctr_name, cipher_name);
+}
+
+static struct crypto_template crypto_ccm_base_tmpl = {
+	.name = "ccm_base",
+	.alloc = crypto_ccm_base_alloc,
+	.free = crypto_ccm_free,
+	.module = THIS_MODULE,
+};
+
+static int crypto_rfc4309_setkey(struct crypto_aead *parent, const u8 *key,
+				 unsigned int keylen)
+{
+	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
+	struct crypto_aead *child = ctx->child;
+	int err;
+
+	if (keylen < 3)
+		return -EINVAL;
+
+	keylen -= 3;
+	memcpy(ctx->nonce, key + keylen, 3);
+
+	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
+				     CRYPTO_TFM_REQ_MASK);
+	err = crypto_aead_setkey(child, key, keylen);
+	crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
+				      CRYPTO_TFM_RES_MASK);
+
+	return err;
+}
+
+static int crypto_rfc4309_setauthsize(struct crypto_aead *parent,
+				      unsigned int authsize)
+{
+	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(parent);
+
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return crypto_aead_setauthsize(ctx->child, authsize);
+}
+
+static struct aead_request *crypto_rfc4309_crypt(struct aead_request *req)
+{
+	struct aead_request *subreq = aead_request_ctx(req);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_rfc4309_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_aead *child = ctx->child;
+	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
+			   crypto_aead_alignmask(child) + 1);
+
+	/* L' */
+	iv[0] = 3;
+
+	memcpy(iv + 1, ctx->nonce, 3);
+	memcpy(iv + 4, req->iv, 8);
+
+	aead_request_set_tfm(subreq, child);
+	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
+				  req->base.data);
+	aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
+	aead_request_set_assoc(subreq, req->assoc, req->assoclen);
+
+	return subreq;
+}
+
+static int crypto_rfc4309_encrypt(struct aead_request *req)
+{
+	req = crypto_rfc4309_crypt(req);
+
+	return crypto_aead_encrypt(req);
+}
+
+static int crypto_rfc4309_decrypt(struct aead_request *req)
+{
+	req = crypto_rfc4309_crypt(req);
+
+	return crypto_aead_decrypt(req);
+}
+
+static int crypto_rfc4309_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_rfc4309_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_aead *aead;
+	unsigned long align;
+
+	aead = crypto_spawn_aead(spawn);
+	if (IS_ERR(aead))
+		return PTR_ERR(aead);
+
+	ctx->child = aead;
+
+	align = crypto_aead_alignmask(aead);
+	align &= ~(crypto_tfm_ctx_alignment() - 1);
+	tfm->crt_aead.reqsize = sizeof(struct aead_request) +
+				ALIGN(crypto_aead_reqsize(aead),
+				      crypto_tfm_ctx_alignment()) +
+				align + 16;
+
+	return 0;
+}
+
+static void crypto_rfc4309_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_rfc4309_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_aead(ctx->child);
+}
+
+static struct crypto_instance *crypto_rfc4309_alloc(struct rtattr **tb)
+{
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	struct crypto_aead_spawn *spawn;
+	struct crypto_alg *alg;
+	const char *ccm_name;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+		return ERR_PTR(-EINVAL);
+
+	ccm_name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(ccm_name);
+	if (IS_ERR(ccm_name))
+		return ERR_PTR(err);
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+	if (!inst)
+		return ERR_PTR(-ENOMEM);
+
+	spawn = crypto_instance_ctx(inst);
+	crypto_set_aead_spawn(spawn, inst);
+	err = crypto_grab_aead(spawn, ccm_name, 0,
+			       crypto_requires_sync(algt->type, algt->mask));
+	if (err)
+		goto out_free_inst;
+
+	alg = crypto_aead_spawn_alg(spawn);
+
+	err = -EINVAL;
+
+	/* We only support 16-byte blocks. */
+	if (alg->cra_aead.ivsize != 16)
+		goto out_drop_alg;
+
+	/* Not a stream cipher? */
+	if (alg->cra_blocksize != 1)
+		goto out_drop_alg;
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+		     "rfc4309(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
+	    snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "rfc4309(%s)", alg->cra_driver_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		goto out_drop_alg;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+	inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = 1;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_nivaead_type;
+
+	inst->alg.cra_aead.ivsize = 8;
+	inst->alg.cra_aead.maxauthsize = 16;
+
+	inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);
+
+	inst->alg.cra_init = crypto_rfc4309_init_tfm;
+	inst->alg.cra_exit = crypto_rfc4309_exit_tfm;
+
+	inst->alg.cra_aead.setkey = crypto_rfc4309_setkey;
+	inst->alg.cra_aead.setauthsize = crypto_rfc4309_setauthsize;
+	inst->alg.cra_aead.encrypt = crypto_rfc4309_encrypt;
+	inst->alg.cra_aead.decrypt = crypto_rfc4309_decrypt;
+
+	inst->alg.cra_aead.geniv = "seqiv";
+
+out:
+	return inst;
+
+out_drop_alg:
+	crypto_drop_aead(spawn);
+out_free_inst:
+	kfree(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static void crypto_rfc4309_free(struct crypto_instance *inst)
+{
+	crypto_drop_spawn(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+
+static struct crypto_template crypto_rfc4309_tmpl = {
+	.name = "rfc4309",
+	.alloc = crypto_rfc4309_alloc,
+	.free = crypto_rfc4309_free,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_ccm_module_init(void)
+{
+	int err;
+
+	err = crypto_register_template(&crypto_ccm_base_tmpl);
+	if (err)
+		goto out;
+
+	err = crypto_register_template(&crypto_ccm_tmpl);
+	if (err)
+		goto out_undo_base;
+
+	err = crypto_register_template(&crypto_rfc4309_tmpl);
+	if (err)
+		goto out_undo_ccm;
+
+out:
+	return err;
+
+out_undo_ccm:
+	crypto_unregister_template(&crypto_ccm_tmpl);
+out_undo_base:
+	crypto_unregister_template(&crypto_ccm_base_tmpl);
+	goto out;
+}
+
+static void __exit crypto_ccm_module_exit(void)
+{
+	crypto_unregister_template(&crypto_rfc4309_tmpl);
+	crypto_unregister_template(&crypto_ccm_tmpl);
+	crypto_unregister_template(&crypto_ccm_base_tmpl);
+}
+
+module_init(crypto_ccm_module_init);
+module_exit(crypto_ccm_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Counter with CBC MAC");
+MODULE_ALIAS("ccm_base");
+MODULE_ALIAS("rfc4309");

+ 331 - 0
crypto/chainiv.c

@@ -0,0 +1,331 @@
+/*
+ * chainiv: Chain IV Generator
+ *
+ * Generate IVs simply be using the last block of the previous encryption.
+ * This is mainly useful for CBC with a synchronous algorithm.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
+enum {
+	CHAINIV_STATE_INUSE = 0,
+};
+
+struct chainiv_ctx {
+	spinlock_t lock;
+	char iv[];
+};
+
+struct async_chainiv_ctx {
+	unsigned long state;
+
+	spinlock_t lock;
+	int err;
+
+	struct crypto_queue queue;
+	struct work_struct postponed;
+
+	char iv[];
+};
+
+static int chainiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+	unsigned int ivsize;
+	int err;
+
+	ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+	ablkcipher_request_set_callback(subreq, req->creq.base.flags &
+						~CRYPTO_TFM_REQ_MAY_SLEEP,
+					req->creq.base.complete,
+					req->creq.base.data);
+	ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
+				     req->creq.nbytes, req->creq.info);
+
+	spin_lock_bh(&ctx->lock);
+
+	ivsize = crypto_ablkcipher_ivsize(geniv);
+
+	memcpy(req->giv, ctx->iv, ivsize);
+	memcpy(subreq->info, ctx->iv, ivsize);
+
+	err = crypto_ablkcipher_encrypt(subreq);
+	if (err)
+		goto unlock;
+
+	memcpy(ctx->iv, subreq->info, ivsize);
+
+unlock:
+	spin_unlock_bh(&ctx->lock);
+
+	return err;
+}
+
+static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+	spin_lock_bh(&ctx->lock);
+	if (crypto_ablkcipher_crt(geniv)->givencrypt !=
+	    chainiv_givencrypt_first)
+		goto unlock;
+
+	crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
+	get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+	spin_unlock_bh(&ctx->lock);
+
+	return chainiv_givencrypt(req);
+}
+
+static int chainiv_init_common(struct crypto_tfm *tfm)
+{
+	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
+
+	return skcipher_geniv_init(tfm);
+}
+
+static int chainiv_init(struct crypto_tfm *tfm)
+{
+	struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	spin_lock_init(&ctx->lock);
+
+	return chainiv_init_common(tfm);
+}
+
+static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx)
+{
+	int queued;
+
+	if (!ctx->queue.qlen) {
+		smp_mb__before_clear_bit();
+		clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
+
+		if (!ctx->queue.qlen ||
+		    test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+			goto out;
+	}
+
+	queued = schedule_work(&ctx->postponed);
+	BUG_ON(!queued);
+
+out:
+	return ctx->err;
+}
+
+static int async_chainiv_postpone_request(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	int err;
+
+	spin_lock_bh(&ctx->lock);
+	err = skcipher_enqueue_givcrypt(&ctx->queue, req);
+	spin_unlock_bh(&ctx->lock);
+
+	if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+		return err;
+
+	ctx->err = err;
+	return async_chainiv_schedule_work(ctx);
+}
+
+static int async_chainiv_givencrypt_tail(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+	unsigned int ivsize = crypto_ablkcipher_ivsize(geniv);
+
+	memcpy(req->giv, ctx->iv, ivsize);
+	memcpy(subreq->info, ctx->iv, ivsize);
+
+	ctx->err = crypto_ablkcipher_encrypt(subreq);
+	if (ctx->err)
+		goto out;
+
+	memcpy(ctx->iv, subreq->info, ivsize);
+
+out:
+	return async_chainiv_schedule_work(ctx);
+}
+
+static int async_chainiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+
+	ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+	ablkcipher_request_set_callback(subreq, req->creq.base.flags,
+					req->creq.base.complete,
+					req->creq.base.data);
+	ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
+				     req->creq.nbytes, req->creq.info);
+
+	if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+		goto postpone;
+
+	if (ctx->queue.qlen) {
+		clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
+		goto postpone;
+	}
+
+	return async_chainiv_givencrypt_tail(req);
+
+postpone:
+	return async_chainiv_postpone_request(req);
+}
+
+static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+	if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
+		goto out;
+
+	if (crypto_ablkcipher_crt(geniv)->givencrypt !=
+	    async_chainiv_givencrypt_first)
+		goto unlock;
+
+	crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
+	get_random_bytes(ctx->iv, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+	clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
+
+out:
+	return async_chainiv_givencrypt(req);
+}
+
+static void async_chainiv_do_postponed(struct work_struct *work)
+{
+	struct async_chainiv_ctx *ctx = container_of(work,
+						     struct async_chainiv_ctx,
+						     postponed);
+	struct skcipher_givcrypt_request *req;
+	struct ablkcipher_request *subreq;
+
+	/* Only handle one request at a time to avoid hogging keventd. */
+	spin_lock_bh(&ctx->lock);
+	req = skcipher_dequeue_givcrypt(&ctx->queue);
+	spin_unlock_bh(&ctx->lock);
+
+	if (!req) {
+		async_chainiv_schedule_work(ctx);
+		return;
+	}
+
+	subreq = skcipher_givcrypt_reqctx(req);
+	subreq->base.flags |= CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	async_chainiv_givencrypt_tail(req);
+}
+
+static int async_chainiv_init(struct crypto_tfm *tfm)
+{
+	struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	spin_lock_init(&ctx->lock);
+
+	crypto_init_queue(&ctx->queue, 100);
+	INIT_WORK(&ctx->postponed, async_chainiv_do_postponed);
+
+	return chainiv_init_common(tfm);
+}
+
+static void async_chainiv_exit(struct crypto_tfm *tfm)
+{
+	struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	BUG_ON(test_bit(CHAINIV_STATE_INUSE, &ctx->state) || ctx->queue.qlen);
+
+	skcipher_geniv_exit(tfm);
+}
+
+static struct crypto_template chainiv_tmpl;
+
+static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
+{
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0);
+	if (IS_ERR(inst))
+		goto out;
+
+	inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first;
+
+	inst->alg.cra_init = chainiv_init;
+	inst->alg.cra_exit = skcipher_geniv_exit;
+
+	inst->alg.cra_ctxsize = sizeof(struct chainiv_ctx);
+
+	if (!crypto_requires_sync(algt->type, algt->mask)) {
+		inst->alg.cra_flags |= CRYPTO_ALG_ASYNC;
+
+		inst->alg.cra_ablkcipher.givencrypt =
+			async_chainiv_givencrypt_first;
+
+		inst->alg.cra_init = async_chainiv_init;
+		inst->alg.cra_exit = async_chainiv_exit;
+
+		inst->alg.cra_ctxsize = sizeof(struct async_chainiv_ctx);
+	}
+
+	inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+
+out:
+	return inst;
+}
+
+static struct crypto_template chainiv_tmpl = {
+	.name = "chainiv",
+	.alloc = chainiv_alloc,
+	.free = skcipher_geniv_free,
+	.module = THIS_MODULE,
+};
+
+static int __init chainiv_module_init(void)
+{
+	return crypto_register_template(&chainiv_tmpl);
+}
+
+static void __exit chainiv_module_exit(void)
+{
+	crypto_unregister_template(&chainiv_tmpl);
+}
+
+module_init(chainiv_module_init);
+module_exit(chainiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Chain IV Generator");

+ 4 - 2
crypto/cryptd.c

@@ -228,7 +228,7 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
 	struct crypto_alg *alg;
 	struct crypto_alg *alg;
 
 
 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
 	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
-				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 		return ERR_PTR(PTR_ERR(alg));
 
 
@@ -236,13 +236,15 @@ static struct crypto_instance *cryptd_alloc_blkcipher(
 	if (IS_ERR(inst))
 	if (IS_ERR(inst))
 		goto out_put_alg;
 		goto out_put_alg;
 
 
-	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC;
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
 	inst->alg.cra_type = &crypto_ablkcipher_type;
 	inst->alg.cra_type = &crypto_ablkcipher_type;
 
 
 	inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize;
 	inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize;
 	inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
 	inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
 	inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
 	inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
 
 
+	inst->alg.cra_ablkcipher.geniv = alg->cra_blkcipher.geniv;
+
 	inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx);
 	inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx);
 
 
 	inst->alg.cra_init = cryptd_blkcipher_init_tfm;
 	inst->alg.cra_init = cryptd_blkcipher_init_tfm;

+ 60 - 10
crypto/crypto_null.c

@@ -16,15 +16,17 @@
  * (at your option) any later version.
  * (at your option) any later version.
  *
  *
  */
  */
+
+#include <crypto/internal/skcipher.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
-#include <linux/crypto.h>
 #include <linux/string.h>
 #include <linux/string.h>
 
 
 #define NULL_KEY_SIZE		0
 #define NULL_KEY_SIZE		0
 #define NULL_BLOCK_SIZE		1
 #define NULL_BLOCK_SIZE		1
 #define NULL_DIGEST_SIZE	0
 #define NULL_DIGEST_SIZE	0
+#define NULL_IV_SIZE		0
 
 
 static int null_compress(struct crypto_tfm *tfm, const u8 *src,
 static int null_compress(struct crypto_tfm *tfm, const u8 *src,
 			 unsigned int slen, u8 *dst, unsigned int *dlen)
 			 unsigned int slen, u8 *dst, unsigned int *dlen)
@@ -55,6 +57,26 @@ static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 	memcpy(dst, src, NULL_BLOCK_SIZE);
 	memcpy(dst, src, NULL_BLOCK_SIZE);
 }
 }
 
 
+static int skcipher_null_crypt(struct blkcipher_desc *desc,
+			       struct scatterlist *dst,
+			       struct scatterlist *src, unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt(desc, &walk);
+
+	while (walk.nbytes) {
+		if (walk.src.virt.addr != walk.dst.virt.addr)
+			memcpy(walk.dst.virt.addr, walk.src.virt.addr,
+			       walk.nbytes);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
 static struct crypto_alg compress_null = {
 static struct crypto_alg compress_null = {
 	.cra_name		=	"compress_null",
 	.cra_name		=	"compress_null",
 	.cra_flags		=	CRYPTO_ALG_TYPE_COMPRESS,
 	.cra_flags		=	CRYPTO_ALG_TYPE_COMPRESS,
@@ -76,6 +98,7 @@ static struct crypto_alg digest_null = {
 	.cra_list		=       LIST_HEAD_INIT(digest_null.cra_list),	
 	.cra_list		=       LIST_HEAD_INIT(digest_null.cra_list),	
 	.cra_u			=	{ .digest = {
 	.cra_u			=	{ .digest = {
 	.dia_digestsize		=	NULL_DIGEST_SIZE,
 	.dia_digestsize		=	NULL_DIGEST_SIZE,
+	.dia_setkey   		=	null_setkey,
 	.dia_init   		=	null_init,
 	.dia_init   		=	null_init,
 	.dia_update 		=	null_update,
 	.dia_update 		=	null_update,
 	.dia_final  		=	null_final } }
 	.dia_final  		=	null_final } }
@@ -96,6 +119,25 @@ static struct crypto_alg cipher_null = {
 	.cia_decrypt		=	null_crypt } }
 	.cia_decrypt		=	null_crypt } }
 };
 };
 
 
+static struct crypto_alg skcipher_null = {
+	.cra_name		=	"ecb(cipher_null)",
+	.cra_driver_name	=	"ecb-cipher_null",
+	.cra_priority		=	100,
+	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_blocksize		=	NULL_BLOCK_SIZE,
+	.cra_type		=	&crypto_blkcipher_type,
+	.cra_ctxsize		=	0,
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(skcipher_null.cra_list),
+	.cra_u			=	{ .blkcipher = {
+	.min_keysize		=	NULL_KEY_SIZE,
+	.max_keysize		=	NULL_KEY_SIZE,
+	.ivsize			=	NULL_IV_SIZE,
+	.setkey			= 	null_setkey,
+	.encrypt		=	skcipher_null_crypt,
+	.decrypt		=	skcipher_null_crypt } }
+};
+
 MODULE_ALIAS("compress_null");
 MODULE_ALIAS("compress_null");
 MODULE_ALIAS("digest_null");
 MODULE_ALIAS("digest_null");
 MODULE_ALIAS("cipher_null");
 MODULE_ALIAS("cipher_null");
@@ -108,27 +150,35 @@ static int __init init(void)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
+	ret = crypto_register_alg(&skcipher_null);
+	if (ret < 0)
+		goto out_unregister_cipher;
+
 	ret = crypto_register_alg(&digest_null);
 	ret = crypto_register_alg(&digest_null);
-	if (ret < 0) {
-		crypto_unregister_alg(&cipher_null);
-		goto out;
-	}
+	if (ret < 0)
+		goto out_unregister_skcipher;
 
 
 	ret = crypto_register_alg(&compress_null);
 	ret = crypto_register_alg(&compress_null);
-	if (ret < 0) {
-		crypto_unregister_alg(&digest_null);
-		crypto_unregister_alg(&cipher_null);
-		goto out;
-	}
+	if (ret < 0)
+		goto out_unregister_digest;
 
 
 out:	
 out:	
 	return ret;
 	return ret;
+
+out_unregister_digest:
+	crypto_unregister_alg(&digest_null);
+out_unregister_skcipher:
+	crypto_unregister_alg(&skcipher_null);
+out_unregister_cipher:
+	crypto_unregister_alg(&cipher_null);
+	goto out;
 }
 }
 
 
 static void __exit fini(void)
 static void __exit fini(void)
 {
 {
 	crypto_unregister_alg(&compress_null);
 	crypto_unregister_alg(&compress_null);
 	crypto_unregister_alg(&digest_null);
 	crypto_unregister_alg(&digest_null);
+	crypto_unregister_alg(&skcipher_null);
 	crypto_unregister_alg(&cipher_null);
 	crypto_unregister_alg(&cipher_null);
 }
 }
 
 

+ 422 - 0
crypto/ctr.c

@@ -0,0 +1,422 @@
+/*
+ * CTR: Counter mode
+ *
+ * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * 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 <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+struct crypto_ctr_ctx {
+	struct crypto_cipher *child;
+};
+
+struct crypto_rfc3686_ctx {
+	struct crypto_blkcipher *child;
+	u8 nonce[CTR_RFC3686_NONCE_SIZE];
+};
+
+static int crypto_ctr_setkey(struct crypto_tfm *parent, const u8 *key,
+			     unsigned int keylen)
+{
+	struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(parent);
+	struct crypto_cipher *child = ctx->child;
+	int err;
+
+	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+				CRYPTO_TFM_REQ_MASK);
+	err = crypto_cipher_setkey(child, key, keylen);
+	crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+			     CRYPTO_TFM_RES_MASK);
+
+	return err;
+}
+
+static void crypto_ctr_crypt_final(struct blkcipher_walk *walk,
+				   struct crypto_cipher *tfm)
+{
+	unsigned int bsize = crypto_cipher_blocksize(tfm);
+	unsigned long alignmask = crypto_cipher_alignmask(tfm);
+	u8 *ctrblk = walk->iv;
+	u8 tmp[bsize + alignmask];
+	u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+
+	crypto_cipher_encrypt_one(tfm, keystream, ctrblk);
+	crypto_xor(keystream, src, nbytes);
+	memcpy(dst, keystream, nbytes);
+
+	crypto_inc(ctrblk, bsize);
+}
+
+static int crypto_ctr_crypt_segment(struct blkcipher_walk *walk,
+				    struct crypto_cipher *tfm)
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		   crypto_cipher_alg(tfm)->cia_encrypt;
+	unsigned int bsize = crypto_cipher_blocksize(tfm);
+	u8 *ctrblk = walk->iv;
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+
+	do {
+		/* create keystream */
+		fn(crypto_cipher_tfm(tfm), dst, ctrblk);
+		crypto_xor(dst, src, bsize);
+
+		/* increment counter in counterblock */
+		crypto_inc(ctrblk, bsize);
+
+		src += bsize;
+		dst += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	return nbytes;
+}
+
+static int crypto_ctr_crypt_inplace(struct blkcipher_walk *walk,
+				    struct crypto_cipher *tfm)
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		   crypto_cipher_alg(tfm)->cia_encrypt;
+	unsigned int bsize = crypto_cipher_blocksize(tfm);
+	unsigned long alignmask = crypto_cipher_alignmask(tfm);
+	unsigned int nbytes = walk->nbytes;
+	u8 *ctrblk = walk->iv;
+	u8 *src = walk->src.virt.addr;
+	u8 tmp[bsize + alignmask];
+	u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+
+	do {
+		/* create keystream */
+		fn(crypto_cipher_tfm(tfm), keystream, ctrblk);
+		crypto_xor(src, keystream, bsize);
+
+		/* increment counter in counterblock */
+		crypto_inc(ctrblk, bsize);
+
+		src += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	return nbytes;
+}
+
+static int crypto_ctr_crypt(struct blkcipher_desc *desc,
+			      struct scatterlist *dst, struct scatterlist *src,
+			      unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	struct crypto_blkcipher *tfm = desc->tfm;
+	struct crypto_ctr_ctx *ctx = crypto_blkcipher_ctx(tfm);
+	struct crypto_cipher *child = ctx->child;
+	unsigned int bsize = crypto_cipher_blocksize(child);
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt_block(desc, &walk, bsize);
+
+	while (walk.nbytes >= bsize) {
+		if (walk.src.virt.addr == walk.dst.virt.addr)
+			nbytes = crypto_ctr_crypt_inplace(&walk, child);
+		else
+			nbytes = crypto_ctr_crypt_segment(&walk, child);
+
+		err = blkcipher_walk_done(desc, &walk, nbytes);
+	}
+
+	if (walk.nbytes) {
+		crypto_ctr_crypt_final(&walk, child);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+static int crypto_ctr_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_cipher *cipher;
+
+	cipher = crypto_spawn_cipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctx->child = cipher;
+
+	return 0;
+}
+
+static void crypto_ctr_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_cipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
+
+	alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
+	if (IS_ERR(alg))
+		return ERR_PTR(PTR_ERR(alg));
+
+	/* Block size must be >= 4 bytes. */
+	err = -EINVAL;
+	if (alg->cra_blocksize < 4)
+		goto out_put_alg;
+
+	/* If this is false we'd fail the alignment of crypto_inc. */
+	if (alg->cra_blocksize % 4)
+		goto out_put_alg;
+
+	inst = crypto_alloc_instance("ctr", alg);
+	if (IS_ERR(inst))
+		goto out;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = 1;
+	inst->alg.cra_alignmask = alg->cra_alignmask | (__alignof__(u32) - 1);
+	inst->alg.cra_type = &crypto_blkcipher_type;
+
+	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+	inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
+	inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
+
+	inst->alg.cra_ctxsize = sizeof(struct crypto_ctr_ctx);
+
+	inst->alg.cra_init = crypto_ctr_init_tfm;
+	inst->alg.cra_exit = crypto_ctr_exit_tfm;
+
+	inst->alg.cra_blkcipher.setkey = crypto_ctr_setkey;
+	inst->alg.cra_blkcipher.encrypt = crypto_ctr_crypt;
+	inst->alg.cra_blkcipher.decrypt = crypto_ctr_crypt;
+
+out:
+	crypto_mod_put(alg);
+	return inst;
+
+out_put_alg:
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static void crypto_ctr_free(struct crypto_instance *inst)
+{
+	crypto_drop_spawn(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+
+static struct crypto_template crypto_ctr_tmpl = {
+	.name = "ctr",
+	.alloc = crypto_ctr_alloc,
+	.free = crypto_ctr_free,
+	.module = THIS_MODULE,
+};
+
+static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key,
+				 unsigned int keylen)
+{
+	struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(parent);
+	struct crypto_blkcipher *child = ctx->child;
+	int err;
+
+	/* the nonce is stored in bytes at end of key */
+	if (keylen < CTR_RFC3686_NONCE_SIZE)
+		return -EINVAL;
+
+	memcpy(ctx->nonce, key + (keylen - CTR_RFC3686_NONCE_SIZE),
+	       CTR_RFC3686_NONCE_SIZE);
+
+	keylen -= CTR_RFC3686_NONCE_SIZE;
+
+	crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
+					  CRYPTO_TFM_REQ_MASK);
+	err = crypto_blkcipher_setkey(child, key, keylen);
+	crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
+				     CRYPTO_TFM_RES_MASK);
+
+	return err;
+}
+
+static int crypto_rfc3686_crypt(struct blkcipher_desc *desc,
+				struct scatterlist *dst,
+				struct scatterlist *src, unsigned int nbytes)
+{
+	struct crypto_blkcipher *tfm = desc->tfm;
+	struct crypto_rfc3686_ctx *ctx = crypto_blkcipher_ctx(tfm);
+	struct crypto_blkcipher *child = ctx->child;
+	unsigned long alignmask = crypto_blkcipher_alignmask(tfm);
+	u8 ivblk[CTR_RFC3686_BLOCK_SIZE + alignmask];
+	u8 *iv = PTR_ALIGN(ivblk + 0, alignmask + 1);
+	u8 *info = desc->info;
+	int err;
+
+	/* set up counter block */
+	memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
+	memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
+
+	/* initialize counter portion of counter block */
+	*(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
+		cpu_to_be32(1);
+
+	desc->tfm = child;
+	desc->info = iv;
+	err = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+	desc->tfm = tfm;
+	desc->info = info;
+
+	return err;
+}
+
+static int crypto_rfc3686_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_blkcipher *cipher;
+
+	cipher = crypto_spawn_blkcipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctx->child = cipher;
+
+	return 0;
+}
+
+static void crypto_rfc3686_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_rfc3686_alloc(struct rtattr **tb)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
+
+	alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
+	err = PTR_ERR(alg);
+	if (IS_ERR(alg))
+		return ERR_PTR(err);
+
+	/* We only support 16-byte blocks. */
+	err = -EINVAL;
+	if (alg->cra_blkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE)
+		goto out_put_alg;
+
+	/* Not a stream cipher? */
+	if (alg->cra_blocksize != 1)
+		goto out_put_alg;
+
+	inst = crypto_alloc_instance("rfc3686", alg);
+	if (IS_ERR(inst))
+		goto out;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = 1;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_blkcipher_type;
+
+	inst->alg.cra_blkcipher.ivsize = CTR_RFC3686_IV_SIZE;
+	inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize
+					      + CTR_RFC3686_NONCE_SIZE;
+	inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize
+					      + CTR_RFC3686_NONCE_SIZE;
+
+	inst->alg.cra_blkcipher.geniv = "seqiv";
+
+	inst->alg.cra_ctxsize = sizeof(struct crypto_rfc3686_ctx);
+
+	inst->alg.cra_init = crypto_rfc3686_init_tfm;
+	inst->alg.cra_exit = crypto_rfc3686_exit_tfm;
+
+	inst->alg.cra_blkcipher.setkey = crypto_rfc3686_setkey;
+	inst->alg.cra_blkcipher.encrypt = crypto_rfc3686_crypt;
+	inst->alg.cra_blkcipher.decrypt = crypto_rfc3686_crypt;
+
+out:
+	crypto_mod_put(alg);
+	return inst;
+
+out_put_alg:
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static struct crypto_template crypto_rfc3686_tmpl = {
+	.name = "rfc3686",
+	.alloc = crypto_rfc3686_alloc,
+	.free = crypto_ctr_free,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_ctr_module_init(void)
+{
+	int err;
+
+	err = crypto_register_template(&crypto_ctr_tmpl);
+	if (err)
+		goto out;
+
+	err = crypto_register_template(&crypto_rfc3686_tmpl);
+	if (err)
+		goto out_drop_ctr;
+
+out:
+	return err;
+
+out_drop_ctr:
+	crypto_unregister_template(&crypto_ctr_tmpl);
+	goto out;
+}
+
+static void __exit crypto_ctr_module_exit(void)
+{
+	crypto_unregister_template(&crypto_rfc3686_tmpl);
+	crypto_unregister_template(&crypto_ctr_tmpl);
+}
+
+module_init(crypto_ctr_module_init);
+module_exit(crypto_ctr_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CTR Counter block mode");
+MODULE_ALIAS("rfc3686");

+ 6 - 11
crypto/des_generic.c

@@ -20,13 +20,7 @@
 #include <linux/crypto.h>
 #include <linux/crypto.h>
 #include <linux/types.h>
 #include <linux/types.h>
 
 
-#define DES_KEY_SIZE		8
-#define DES_EXPKEY_WORDS	32
-#define DES_BLOCK_SIZE		8
-
-#define DES3_EDE_KEY_SIZE	(3 * DES_KEY_SIZE)
-#define DES3_EDE_EXPKEY_WORDS	(3 * DES_EXPKEY_WORDS)
-#define DES3_EDE_BLOCK_SIZE	DES_BLOCK_SIZE
+#include <crypto/des.h>
 
 
 #define ROL(x, r) ((x) = rol32((x), (r)))
 #define ROL(x, r) ((x) = rol32((x), (r)))
 #define ROR(x, r) ((x) = ror32((x), (r)))
 #define ROR(x, r) ((x) = ror32((x), (r)))
@@ -634,7 +628,7 @@ static const u32 S8[64] = {
  *   Choice 1 has operated on the key.
  *   Choice 1 has operated on the key.
  *
  *
  */
  */
-static unsigned long ekey(u32 *pe, const u8 *k)
+unsigned long des_ekey(u32 *pe, const u8 *k)
 {
 {
 	/* K&R: long is at least 32 bits */
 	/* K&R: long is at least 32 bits */
 	unsigned long a, b, c, d, w;
 	unsigned long a, b, c, d, w;
@@ -709,6 +703,7 @@ static unsigned long ekey(u32 *pe, const u8 *k)
 	/* Zero if weak key */
 	/* Zero if weak key */
 	return w;
 	return w;
 }
 }
+EXPORT_SYMBOL_GPL(des_ekey);
 
 
 /*
 /*
  * Decryption key expansion
  * Decryption key expansion
@@ -792,7 +787,7 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
 	int ret;
 	int ret;
 
 
 	/* Expand to tmp */
 	/* Expand to tmp */
-	ret = ekey(tmp, key);
+	ret = des_ekey(tmp, key);
 
 
 	if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
 	if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
 		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
 		*flags |= CRYPTO_TFM_RES_WEAK_KEY;
@@ -879,9 +874,9 @@ static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
+	des_ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
 	dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
 	dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
-	ekey(expkey, key);
+	des_ekey(expkey, key);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 3
crypto/digest.c

@@ -12,6 +12,7 @@
  *
  *
  */
  */
 
 
+#include <crypto/scatterwalk.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/hardirq.h>
 #include <linux/hardirq.h>
@@ -20,9 +21,6 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 
 
-#include "internal.h"
-#include "scatterwalk.h"
-
 static int init(struct hash_desc *desc)
 static int init(struct hash_desc *desc)
 {
 {
 	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
 	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);

+ 264 - 0
crypto/eseqiv.c

@@ -0,0 +1,264 @@
+/*
+ * eseqiv: Encrypted Sequence Number IV Generator
+ *
+ * This generator generates an IV based on a sequence number by xoring it
+ * with a salt and then encrypting it with the same key as used to encrypt
+ * the plain text.  This algorithm requires that the block size be equal
+ * to the IV size.  It is mainly useful for CBC.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+struct eseqiv_request_ctx {
+	struct scatterlist src[2];
+	struct scatterlist dst[2];
+	char tail[];
+};
+
+struct eseqiv_ctx {
+	spinlock_t lock;
+	unsigned int reqoff;
+	char salt[];
+};
+
+static void eseqiv_complete2(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req);
+
+	memcpy(req->giv, PTR_ALIGN((u8 *)reqctx->tail,
+			 crypto_ablkcipher_alignmask(geniv) + 1),
+	       crypto_ablkcipher_ivsize(geniv));
+}
+
+static void eseqiv_complete(struct crypto_async_request *base, int err)
+{
+	struct skcipher_givcrypt_request *req = base->data;
+
+	if (err)
+		goto out;
+
+	eseqiv_complete2(req);
+
+out:
+	skcipher_givcrypt_complete(req, err);
+}
+
+static void eseqiv_chain(struct scatterlist *head, struct scatterlist *sg,
+			 int chain)
+{
+	if (chain) {
+		head->length += sg->length;
+		sg = scatterwalk_sg_next(sg);
+	}
+
+	if (sg)
+		scatterwalk_sg_chain(head, 2, sg);
+	else
+		sg_mark_end(head);
+}
+
+static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req);
+	struct ablkcipher_request *subreq;
+	crypto_completion_t complete;
+	void *data;
+	struct scatterlist *osrc, *odst;
+	struct scatterlist *dst;
+	struct page *srcp;
+	struct page *dstp;
+	u8 *giv;
+	u8 *vsrc;
+	u8 *vdst;
+	__be64 seq;
+	unsigned int ivsize;
+	unsigned int len;
+	int err;
+
+	subreq = (void *)(reqctx->tail + ctx->reqoff);
+	ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+
+	giv = req->giv;
+	complete = req->creq.base.complete;
+	data = req->creq.base.data;
+
+	osrc = req->creq.src;
+	odst = req->creq.dst;
+	srcp = sg_page(osrc);
+	dstp = sg_page(odst);
+	vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + osrc->offset;
+	vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + odst->offset;
+
+	ivsize = crypto_ablkcipher_ivsize(geniv);
+
+	if (vsrc != giv + ivsize && vdst != giv + ivsize) {
+		giv = PTR_ALIGN((u8 *)reqctx->tail,
+				crypto_ablkcipher_alignmask(geniv) + 1);
+		complete = eseqiv_complete;
+		data = req;
+	}
+
+	ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
+					data);
+
+	sg_init_table(reqctx->src, 2);
+	sg_set_buf(reqctx->src, giv, ivsize);
+	eseqiv_chain(reqctx->src, osrc, vsrc == giv + ivsize);
+
+	dst = reqctx->src;
+	if (osrc != odst) {
+		sg_init_table(reqctx->dst, 2);
+		sg_set_buf(reqctx->dst, giv, ivsize);
+		eseqiv_chain(reqctx->dst, odst, vdst == giv + ivsize);
+
+		dst = reqctx->dst;
+	}
+
+	ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
+				     req->creq.nbytes, req->creq.info);
+
+	memcpy(req->creq.info, ctx->salt, ivsize);
+
+	len = ivsize;
+	if (ivsize > sizeof(u64)) {
+		memset(req->giv, 0, ivsize - sizeof(u64));
+		len = sizeof(u64);
+	}
+	seq = cpu_to_be64(req->seq);
+	memcpy(req->giv + ivsize - len, &seq, len);
+
+	err = crypto_ablkcipher_encrypt(subreq);
+	if (err)
+		goto out;
+
+	eseqiv_complete2(req);
+
+out:
+	return err;
+}
+
+static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+	spin_lock_bh(&ctx->lock);
+	if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
+		goto unlock;
+
+	crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
+	get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+	spin_unlock_bh(&ctx->lock);
+
+	return eseqiv_givencrypt(req);
+}
+
+static int eseqiv_init(struct crypto_tfm *tfm)
+{
+	struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
+	struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	unsigned long alignmask;
+	unsigned int reqsize;
+
+	spin_lock_init(&ctx->lock);
+
+	alignmask = crypto_tfm_ctx_alignment() - 1;
+	reqsize = sizeof(struct eseqiv_request_ctx);
+
+	if (alignmask & reqsize) {
+		alignmask &= reqsize;
+		alignmask--;
+	}
+
+	alignmask = ~alignmask;
+	alignmask &= crypto_ablkcipher_alignmask(geniv);
+
+	reqsize += alignmask;
+	reqsize += crypto_ablkcipher_ivsize(geniv);
+	reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
+
+	ctx->reqoff = reqsize - sizeof(struct eseqiv_request_ctx);
+
+	tfm->crt_ablkcipher.reqsize = reqsize +
+				      sizeof(struct ablkcipher_request);
+
+	return skcipher_geniv_init(tfm);
+}
+
+static struct crypto_template eseqiv_tmpl;
+
+static struct crypto_instance *eseqiv_alloc(struct rtattr **tb)
+{
+	struct crypto_instance *inst;
+	int err;
+
+	inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
+	if (IS_ERR(inst))
+		goto out;
+
+	err = -EINVAL;
+	if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
+		goto free_inst;
+
+	inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first;
+
+	inst->alg.cra_init = eseqiv_init;
+	inst->alg.cra_exit = skcipher_geniv_exit;
+
+	inst->alg.cra_ctxsize = sizeof(struct eseqiv_ctx);
+	inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+
+out:
+	return inst;
+
+free_inst:
+	skcipher_geniv_free(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static struct crypto_template eseqiv_tmpl = {
+	.name = "eseqiv",
+	.alloc = eseqiv_alloc,
+	.free = skcipher_geniv_free,
+	.module = THIS_MODULE,
+};
+
+static int __init eseqiv_module_init(void)
+{
+	return crypto_register_template(&eseqiv_tmpl);
+}
+
+static void __exit eseqiv_module_exit(void)
+{
+	crypto_unregister_template(&eseqiv_tmpl);
+}
+
+module_init(eseqiv_module_init);
+module_exit(eseqiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator");

+ 823 - 0
crypto/gcm.c

@@ -0,0 +1,823 @@
+/*
+ * GCM: Galois/Counter Mode.
+ *
+ * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <crypto/gf128mul.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+struct gcm_instance_ctx {
+	struct crypto_skcipher_spawn ctr;
+};
+
+struct crypto_gcm_ctx {
+	struct crypto_ablkcipher *ctr;
+	struct gf128mul_4k *gf128;
+};
+
+struct crypto_rfc4106_ctx {
+	struct crypto_aead *child;
+	u8 nonce[4];
+};
+
+struct crypto_gcm_ghash_ctx {
+	u32 bytes;
+	u32 flags;
+	struct gf128mul_4k *gf128;
+	u8 buffer[16];
+};
+
+struct crypto_gcm_req_priv_ctx {
+	u8 auth_tag[16];
+	u8 iauth_tag[16];
+	struct scatterlist src[2];
+	struct scatterlist dst[2];
+	struct crypto_gcm_ghash_ctx ghash;
+	struct ablkcipher_request abreq;
+};
+
+struct crypto_gcm_setkey_result {
+	int err;
+	struct completion completion;
+};
+
+static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx(
+	struct aead_request *req)
+{
+	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
+
+	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
+}
+
+static void crypto_gcm_ghash_init(struct crypto_gcm_ghash_ctx *ctx, u32 flags,
+				  struct gf128mul_4k *gf128)
+{
+	ctx->bytes = 0;
+	ctx->flags = flags;
+	ctx->gf128 = gf128;
+	memset(ctx->buffer, 0, 16);
+}
+
+static void crypto_gcm_ghash_update(struct crypto_gcm_ghash_ctx *ctx,
+				    const u8 *src, unsigned int srclen)
+{
+	u8 *dst = ctx->buffer;
+
+	if (ctx->bytes) {
+		int n = min(srclen, ctx->bytes);
+		u8 *pos = dst + (16 - ctx->bytes);
+
+		ctx->bytes -= n;
+		srclen -= n;
+
+		while (n--)
+			*pos++ ^= *src++;
+
+		if (!ctx->bytes)
+			gf128mul_4k_lle((be128 *)dst, ctx->gf128);
+	}
+
+	while (srclen >= 16) {
+		crypto_xor(dst, src, 16);
+		gf128mul_4k_lle((be128 *)dst, ctx->gf128);
+		src += 16;
+		srclen -= 16;
+	}
+
+	if (srclen) {
+		ctx->bytes = 16 - srclen;
+		while (srclen--)
+			*dst++ ^= *src++;
+	}
+}
+
+static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx,
+				       struct scatterlist *sg, int len)
+{
+	struct scatter_walk walk;
+	u8 *src;
+	int n;
+
+	if (!len)
+		return;
+
+	scatterwalk_start(&walk, sg);
+
+	while (len) {
+		n = scatterwalk_clamp(&walk, len);
+
+		if (!n) {
+			scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg));
+			n = scatterwalk_clamp(&walk, len);
+		}
+
+		src = scatterwalk_map(&walk, 0);
+
+		crypto_gcm_ghash_update(ctx, src, n);
+		len -= n;
+
+		scatterwalk_unmap(src, 0);
+		scatterwalk_advance(&walk, n);
+		scatterwalk_done(&walk, 0, len);
+		if (len)
+			crypto_yield(ctx->flags);
+	}
+}
+
+static void crypto_gcm_ghash_flush(struct crypto_gcm_ghash_ctx *ctx)
+{
+	u8 *dst = ctx->buffer;
+
+	if (ctx->bytes) {
+		u8 *tmp = dst + (16 - ctx->bytes);
+
+		while (ctx->bytes--)
+			*tmp++ ^= 0;
+
+		gf128mul_4k_lle((be128 *)dst, ctx->gf128);
+	}
+
+	ctx->bytes = 0;
+}
+
+static void crypto_gcm_ghash_final_xor(struct crypto_gcm_ghash_ctx *ctx,
+				       unsigned int authlen,
+				       unsigned int cryptlen, u8 *dst)
+{
+	u8 *buf = ctx->buffer;
+	u128 lengths;
+
+	lengths.a = cpu_to_be64(authlen * 8);
+	lengths.b = cpu_to_be64(cryptlen * 8);
+
+	crypto_gcm_ghash_flush(ctx);
+	crypto_xor(buf, (u8 *)&lengths, 16);
+	gf128mul_4k_lle((be128 *)buf, ctx->gf128);
+	crypto_xor(dst, buf, 16);
+}
+
+static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err)
+{
+	struct crypto_gcm_setkey_result *result = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	result->err = err;
+	complete(&result->completion);
+}
+
+static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
+			     unsigned int keylen)
+{
+	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_ablkcipher *ctr = ctx->ctr;
+	struct {
+		be128 hash;
+		u8 iv[8];
+
+		struct crypto_gcm_setkey_result result;
+
+		struct scatterlist sg[1];
+		struct ablkcipher_request req;
+	} *data;
+	int err;
+
+	crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
+	crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
+				   CRYPTO_TFM_REQ_MASK);
+
+	err = crypto_ablkcipher_setkey(ctr, key, keylen);
+	if (err)
+		return err;
+
+	crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
+				       CRYPTO_TFM_RES_MASK);
+
+	data = kzalloc(sizeof(*data) + crypto_ablkcipher_reqsize(ctr),
+		       GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	init_completion(&data->result.completion);
+	sg_init_one(data->sg, &data->hash, sizeof(data->hash));
+	ablkcipher_request_set_tfm(&data->req, ctr);
+	ablkcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
+						    CRYPTO_TFM_REQ_MAY_BACKLOG,
+					crypto_gcm_setkey_done,
+					&data->result);
+	ablkcipher_request_set_crypt(&data->req, data->sg, data->sg,
+				     sizeof(data->hash), data->iv);
+
+	err = crypto_ablkcipher_encrypt(&data->req);
+	if (err == -EINPROGRESS || err == -EBUSY) {
+		err = wait_for_completion_interruptible(
+			&data->result.completion);
+		if (!err)
+			err = data->result.err;
+	}
+
+	if (err)
+		goto out;
+
+	if (ctx->gf128 != NULL)
+		gf128mul_free_4k(ctx->gf128);
+
+	ctx->gf128 = gf128mul_init_4k_lle(&data->hash);
+
+	if (ctx->gf128 == NULL)
+		err = -ENOMEM;
+
+out:
+	kfree(data);
+	return err;
+}
+
+static int crypto_gcm_setauthsize(struct crypto_aead *tfm,
+				  unsigned int authsize)
+{
+	switch (authsize) {
+	case 4:
+	case 8:
+	case 12:
+	case 13:
+	case 14:
+	case 15:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
+				  struct aead_request *req,
+				  unsigned int cryptlen)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+	u32 flags = req->base.tfm->crt_flags;
+	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+	struct scatterlist *dst;
+	__be32 counter = cpu_to_be32(1);
+
+	memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
+	memcpy(req->iv + 12, &counter, 4);
+
+	sg_init_table(pctx->src, 2);
+	sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
+	scatterwalk_sg_chain(pctx->src, 2, req->src);
+
+	dst = pctx->src;
+	if (req->src != req->dst) {
+		sg_init_table(pctx->dst, 2);
+		sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
+		scatterwalk_sg_chain(pctx->dst, 2, req->dst);
+		dst = pctx->dst;
+	}
+
+	ablkcipher_request_set_tfm(ablk_req, ctx->ctr);
+	ablkcipher_request_set_crypt(ablk_req, pctx->src, dst,
+				     cryptlen + sizeof(pctx->auth_tag),
+				     req->iv);
+
+	crypto_gcm_ghash_init(ghash, flags, ctx->gf128);
+
+	crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen);
+	crypto_gcm_ghash_flush(ghash);
+}
+
+static int crypto_gcm_hash(struct aead_request *req)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+	u8 *auth_tag = pctx->auth_tag;
+	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+
+	crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen);
+	crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen,
+				   auth_tag);
+
+	scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen,
+				 crypto_aead_authsize(aead), 1);
+	return 0;
+}
+
+static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err)
+{
+	struct aead_request *req = areq->data;
+
+	if (!err)
+		err = crypto_gcm_hash(req);
+
+	aead_request_complete(req, err);
+}
+
+static int crypto_gcm_encrypt(struct aead_request *req)
+{
+	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+	struct ablkcipher_request *abreq = &pctx->abreq;
+	int err;
+
+	crypto_gcm_init_crypt(abreq, req, req->cryptlen);
+	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
+					crypto_gcm_encrypt_done, req);
+
+	err = crypto_ablkcipher_encrypt(abreq);
+	if (err)
+		return err;
+
+	return crypto_gcm_hash(req);
+}
+
+static int crypto_gcm_verify(struct aead_request *req)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+	u8 *auth_tag = pctx->auth_tag;
+	u8 *iauth_tag = pctx->iauth_tag;
+	unsigned int authsize = crypto_aead_authsize(aead);
+	unsigned int cryptlen = req->cryptlen - authsize;
+
+	crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag);
+
+	authsize = crypto_aead_authsize(aead);
+	scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
+	return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
+}
+
+static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err)
+{
+	struct aead_request *req = areq->data;
+
+	if (!err)
+		err = crypto_gcm_verify(req);
+
+	aead_request_complete(req, err);
+}
+
+static int crypto_gcm_decrypt(struct aead_request *req)
+{
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+	struct ablkcipher_request *abreq = &pctx->abreq;
+	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
+	unsigned int cryptlen = req->cryptlen;
+	unsigned int authsize = crypto_aead_authsize(aead);
+	int err;
+
+	if (cryptlen < authsize)
+		return -EINVAL;
+	cryptlen -= authsize;
+
+	crypto_gcm_init_crypt(abreq, req, cryptlen);
+	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
+					crypto_gcm_decrypt_done, req);
+
+	crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen);
+
+	err = crypto_ablkcipher_decrypt(abreq);
+	if (err)
+		return err;
+
+	return crypto_gcm_verify(req);
+}
+
+static int crypto_gcm_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct gcm_instance_ctx *ictx = crypto_instance_ctx(inst);
+	struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_ablkcipher *ctr;
+	unsigned long align;
+	int err;
+
+	ctr = crypto_spawn_skcipher(&ictx->ctr);
+	err = PTR_ERR(ctr);
+	if (IS_ERR(ctr))
+		return err;
+
+	ctx->ctr = ctr;
+	ctx->gf128 = NULL;
+
+	align = crypto_tfm_alg_alignmask(tfm);
+	align &= ~(crypto_tfm_ctx_alignment() - 1);
+	tfm->crt_aead.reqsize = align +
+				sizeof(struct crypto_gcm_req_priv_ctx) +
+				crypto_ablkcipher_reqsize(ctr);
+
+	return 0;
+}
+
+static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if (ctx->gf128 != NULL)
+		gf128mul_free_4k(ctx->gf128);
+
+	crypto_free_ablkcipher(ctx->ctr);
+}
+
+static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
+						       const char *full_name,
+						       const char *ctr_name)
+{
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	struct crypto_alg *ctr;
+	struct gcm_instance_ctx *ctx;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+		return ERR_PTR(-EINVAL);
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+	if (!inst)
+		return ERR_PTR(-ENOMEM);
+
+	ctx = crypto_instance_ctx(inst);
+	crypto_set_skcipher_spawn(&ctx->ctr, inst);
+	err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0,
+				   crypto_requires_sync(algt->type,
+							algt->mask));
+	if (err)
+		goto err_free_inst;
+
+	ctr = crypto_skcipher_spawn_alg(&ctx->ctr);
+
+	/* We only support 16-byte blocks. */
+	if (ctr->cra_ablkcipher.ivsize != 16)
+		goto out_put_ctr;
+
+	/* Not a stream cipher? */
+	err = -EINVAL;
+	if (ctr->cra_blocksize != 1)
+		goto out_put_ctr;
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "gcm_base(%s)", ctr->cra_driver_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		goto out_put_ctr;
+
+	memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+	inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
+	inst->alg.cra_priority = ctr->cra_priority;
+	inst->alg.cra_blocksize = 1;
+	inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1);
+	inst->alg.cra_type = &crypto_aead_type;
+	inst->alg.cra_aead.ivsize = 16;
+	inst->alg.cra_aead.maxauthsize = 16;
+	inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
+	inst->alg.cra_init = crypto_gcm_init_tfm;
+	inst->alg.cra_exit = crypto_gcm_exit_tfm;
+	inst->alg.cra_aead.setkey = crypto_gcm_setkey;
+	inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize;
+	inst->alg.cra_aead.encrypt = crypto_gcm_encrypt;
+	inst->alg.cra_aead.decrypt = crypto_gcm_decrypt;
+
+out:
+	return inst;
+
+out_put_ctr:
+	crypto_drop_skcipher(&ctx->ctr);
+err_free_inst:
+	kfree(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb)
+{
+	int err;
+	const char *cipher_name;
+	char ctr_name[CRYPTO_MAX_ALG_NAME];
+	char full_name[CRYPTO_MAX_ALG_NAME];
+
+	cipher_name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(cipher_name);
+	if (IS_ERR(cipher_name))
+		return ERR_PTR(err);
+
+	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	return crypto_gcm_alloc_common(tb, full_name, ctr_name);
+}
+
+static void crypto_gcm_free(struct crypto_instance *inst)
+{
+	struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+	crypto_drop_skcipher(&ctx->ctr);
+	kfree(inst);
+}
+
+static struct crypto_template crypto_gcm_tmpl = {
+	.name = "gcm",
+	.alloc = crypto_gcm_alloc,
+	.free = crypto_gcm_free,
+	.module = THIS_MODULE,
+};
+
+static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
+{
+	int err;
+	const char *ctr_name;
+	char full_name[CRYPTO_MAX_ALG_NAME];
+
+	ctr_name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(ctr_name);
+	if (IS_ERR(ctr_name))
+		return ERR_PTR(err);
+
+	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)",
+		     ctr_name) >= CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	return crypto_gcm_alloc_common(tb, full_name, ctr_name);
+}
+
+static struct crypto_template crypto_gcm_base_tmpl = {
+	.name = "gcm_base",
+	.alloc = crypto_gcm_base_alloc,
+	.free = crypto_gcm_free,
+	.module = THIS_MODULE,
+};
+
+static int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key,
+				 unsigned int keylen)
+{
+	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
+	struct crypto_aead *child = ctx->child;
+	int err;
+
+	if (keylen < 4)
+		return -EINVAL;
+
+	keylen -= 4;
+	memcpy(ctx->nonce, key + keylen, 4);
+
+	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
+				     CRYPTO_TFM_REQ_MASK);
+	err = crypto_aead_setkey(child, key, keylen);
+	crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
+				      CRYPTO_TFM_RES_MASK);
+
+	return err;
+}
+
+static int crypto_rfc4106_setauthsize(struct crypto_aead *parent,
+				      unsigned int authsize)
+{
+	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
+
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return crypto_aead_setauthsize(ctx->child, authsize);
+}
+
+static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req)
+{
+	struct aead_request *subreq = aead_request_ctx(req);
+	struct crypto_aead *aead = crypto_aead_reqtfm(req);
+	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
+	struct crypto_aead *child = ctx->child;
+	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
+			   crypto_aead_alignmask(child) + 1);
+
+	memcpy(iv, ctx->nonce, 4);
+	memcpy(iv + 4, req->iv, 8);
+
+	aead_request_set_tfm(subreq, child);
+	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
+				  req->base.data);
+	aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
+	aead_request_set_assoc(subreq, req->assoc, req->assoclen);
+
+	return subreq;
+}
+
+static int crypto_rfc4106_encrypt(struct aead_request *req)
+{
+	req = crypto_rfc4106_crypt(req);
+
+	return crypto_aead_encrypt(req);
+}
+
+static int crypto_rfc4106_decrypt(struct aead_request *req)
+{
+	req = crypto_rfc4106_crypt(req);
+
+	return crypto_aead_decrypt(req);
+}
+
+static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_aead *aead;
+	unsigned long align;
+
+	aead = crypto_spawn_aead(spawn);
+	if (IS_ERR(aead))
+		return PTR_ERR(aead);
+
+	ctx->child = aead;
+
+	align = crypto_aead_alignmask(aead);
+	align &= ~(crypto_tfm_ctx_alignment() - 1);
+	tfm->crt_aead.reqsize = sizeof(struct aead_request) +
+				ALIGN(crypto_aead_reqsize(aead),
+				      crypto_tfm_ctx_alignment()) +
+				align + 16;
+
+	return 0;
+}
+
+static void crypto_rfc4106_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_aead(ctx->child);
+}
+
+static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb)
+{
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	struct crypto_aead_spawn *spawn;
+	struct crypto_alg *alg;
+	const char *ccm_name;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+		return ERR_PTR(-EINVAL);
+
+	ccm_name = crypto_attr_alg_name(tb[1]);
+	err = PTR_ERR(ccm_name);
+	if (IS_ERR(ccm_name))
+		return ERR_PTR(err);
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+	if (!inst)
+		return ERR_PTR(-ENOMEM);
+
+	spawn = crypto_instance_ctx(inst);
+	crypto_set_aead_spawn(spawn, inst);
+	err = crypto_grab_aead(spawn, ccm_name, 0,
+			       crypto_requires_sync(algt->type, algt->mask));
+	if (err)
+		goto out_free_inst;
+
+	alg = crypto_aead_spawn_alg(spawn);
+
+	err = -EINVAL;
+
+	/* We only support 16-byte blocks. */
+	if (alg->cra_aead.ivsize != 16)
+		goto out_drop_alg;
+
+	/* Not a stream cipher? */
+	if (alg->cra_blocksize != 1)
+		goto out_drop_alg;
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+		     "rfc4106(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
+	    snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "rfc4106(%s)", alg->cra_driver_name) >=
+	    CRYPTO_MAX_ALG_NAME)
+		goto out_drop_alg;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+	inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+	inst->alg.cra_priority = alg->cra_priority;
+	inst->alg.cra_blocksize = 1;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_nivaead_type;
+
+	inst->alg.cra_aead.ivsize = 8;
+	inst->alg.cra_aead.maxauthsize = 16;
+
+	inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
+
+	inst->alg.cra_init = crypto_rfc4106_init_tfm;
+	inst->alg.cra_exit = crypto_rfc4106_exit_tfm;
+
+	inst->alg.cra_aead.setkey = crypto_rfc4106_setkey;
+	inst->alg.cra_aead.setauthsize = crypto_rfc4106_setauthsize;
+	inst->alg.cra_aead.encrypt = crypto_rfc4106_encrypt;
+	inst->alg.cra_aead.decrypt = crypto_rfc4106_decrypt;
+
+	inst->alg.cra_aead.geniv = "seqiv";
+
+out:
+	return inst;
+
+out_drop_alg:
+	crypto_drop_aead(spawn);
+out_free_inst:
+	kfree(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static void crypto_rfc4106_free(struct crypto_instance *inst)
+{
+	crypto_drop_spawn(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+
+static struct crypto_template crypto_rfc4106_tmpl = {
+	.name = "rfc4106",
+	.alloc = crypto_rfc4106_alloc,
+	.free = crypto_rfc4106_free,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_gcm_module_init(void)
+{
+	int err;
+
+	err = crypto_register_template(&crypto_gcm_base_tmpl);
+	if (err)
+		goto out;
+
+	err = crypto_register_template(&crypto_gcm_tmpl);
+	if (err)
+		goto out_undo_base;
+
+	err = crypto_register_template(&crypto_rfc4106_tmpl);
+	if (err)
+		goto out_undo_gcm;
+
+out:
+	return err;
+
+out_undo_gcm:
+	crypto_unregister_template(&crypto_gcm_tmpl);
+out_undo_base:
+	crypto_unregister_template(&crypto_gcm_base_tmpl);
+	goto out;
+}
+
+static void __exit crypto_gcm_module_exit(void)
+{
+	crypto_unregister_template(&crypto_rfc4106_tmpl);
+	crypto_unregister_template(&crypto_gcm_tmpl);
+	crypto_unregister_template(&crypto_gcm_base_tmpl);
+}
+
+module_init(crypto_gcm_module_init);
+module_exit(crypto_gcm_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Galois/Counter Mode");
+MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>");
+MODULE_ALIAS("gcm_base");
+MODULE_ALIAS("rfc4106");

+ 2 - 1
crypto/hmac.c

@@ -17,6 +17,7 @@
  */
  */
 
 
 #include <crypto/algapi.h>
 #include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -160,7 +161,7 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
 
 
 	sg_init_table(sg1, 2);
 	sg_init_table(sg1, 2);
 	sg_set_buf(sg1, ipad, bs);
 	sg_set_buf(sg1, ipad, bs);
-	sg_set_page(&sg1[1], (void *) sg, 0, 0);
+	scatterwalk_sg_chain(sg1, 2, sg);
 
 
 	sg_init_table(sg2, 1);
 	sg_init_table(sg2, 1);
 	sg_set_buf(sg2, opad, bs + ds);
 	sg_set_buf(sg2, opad, bs + ds);

+ 2 - 29
crypto/internal.h

@@ -25,7 +25,6 @@
 #include <linux/notifier.h>
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
-#include <asm/kmap_types.h>
 
 
 /* Crypto notification events. */
 /* Crypto notification events. */
 enum {
 enum {
@@ -50,34 +49,6 @@ extern struct list_head crypto_alg_list;
 extern struct rw_semaphore crypto_alg_sem;
 extern struct rw_semaphore crypto_alg_sem;
 extern struct blocking_notifier_head crypto_chain;
 extern struct blocking_notifier_head crypto_chain;
 
 
-static inline enum km_type crypto_kmap_type(int out)
-{
-	enum km_type type;
-
-	if (in_softirq())
-		type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0;
-	else
-		type = out * (KM_USER1 - KM_USER0) + KM_USER0;
-
-	return type;
-}
-
-static inline void *crypto_kmap(struct page *page, int out)
-{
-	return kmap_atomic(page, crypto_kmap_type(out));
-}
-
-static inline void crypto_kunmap(void *vaddr, int out)
-{
-	kunmap_atomic(vaddr, crypto_kmap_type(out));
-}
-
-static inline void crypto_yield(u32 flags)
-{
-	if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
-		cond_resched();
-}
-
 #ifdef CONFIG_PROC_FS
 #ifdef CONFIG_PROC_FS
 void __init crypto_init_proc(void);
 void __init crypto_init_proc(void);
 void __exit crypto_exit_proc(void);
 void __exit crypto_exit_proc(void);
@@ -122,6 +93,8 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm);
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
 void crypto_exit_compress_ops(struct crypto_tfm *tfm);
 void crypto_exit_compress_ops(struct crypto_tfm *tfm);
 
 
+void crypto_larval_kill(struct crypto_alg *alg);
+struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask);
 void crypto_larval_error(const char *name, u32 type, u32 mask);
 void crypto_larval_error(const char *name, u32 type, u32 mask);
 
 
 void crypto_shoot_alg(struct crypto_alg *alg);
 void crypto_shoot_alg(struct crypto_alg *alg);

+ 106 - 0
crypto/lzo.c

@@ -0,0 +1,106 @@
+/*
+ * Cryptographic API.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/lzo.h>
+
+struct lzo_ctx {
+	void *lzo_comp_mem;
+};
+
+static int lzo_init(struct crypto_tfm *tfm)
+{
+	struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS);
+	if (!ctx->lzo_comp_mem)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void lzo_exit(struct crypto_tfm *tfm)
+{
+	struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	vfree(ctx->lzo_comp_mem);
+}
+
+static int lzo_compress(struct crypto_tfm *tfm, const u8 *src,
+			    unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+	struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
+	size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
+	int err;
+
+	err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx->lzo_comp_mem);
+
+	if (err != LZO_E_OK)
+		return -EINVAL;
+
+	*dlen = tmp_len;
+	return 0;
+}
+
+static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src,
+			      unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+	int err;
+	size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
+
+	err = lzo1x_decompress_safe(src, slen, dst, &tmp_len);
+
+	if (err != LZO_E_OK)
+		return -EINVAL;
+
+	*dlen = tmp_len;
+	return 0;
+
+}
+
+static struct crypto_alg alg = {
+	.cra_name		= "lzo",
+	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
+	.cra_ctxsize		= sizeof(struct lzo_ctx),
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
+	.cra_init		= lzo_init,
+	.cra_exit		= lzo_exit,
+	.cra_u			= { .compress = {
+	.coa_compress 		= lzo_compress,
+	.coa_decompress  	= lzo_decompress } }
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LZO Compression Algorithm");

+ 24 - 81
crypto/pcbc.c

@@ -24,7 +24,6 @@
 
 
 struct crypto_pcbc_ctx {
 struct crypto_pcbc_ctx {
 	struct crypto_cipher *child;
 	struct crypto_cipher *child;
-	void (*xor)(u8 *dst, const u8 *src, unsigned int bs);
 };
 };
 
 
 static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
 static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
@@ -45,9 +44,7 @@ static int crypto_pcbc_setkey(struct crypto_tfm *parent, const u8 *key,
 
 
 static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
 static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
 				       struct blkcipher_walk *walk,
 				       struct blkcipher_walk *walk,
-				       struct crypto_cipher *tfm,
-				       void (*xor)(u8 *, const u8 *,
-						   unsigned int))
+				       struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_encrypt;
 		crypto_cipher_alg(tfm)->cia_encrypt;
@@ -58,10 +55,10 @@ static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
 	u8 *iv = walk->iv;
 	u8 *iv = walk->iv;
 
 
 	do {
 	do {
-		xor(iv, src, bsize);
+		crypto_xor(iv, src, bsize);
 		fn(crypto_cipher_tfm(tfm), dst, iv);
 		fn(crypto_cipher_tfm(tfm), dst, iv);
 		memcpy(iv, dst, bsize);
 		memcpy(iv, dst, bsize);
-		xor(iv, src, bsize);
+		crypto_xor(iv, src, bsize);
 
 
 		src += bsize;
 		src += bsize;
 		dst += bsize;
 		dst += bsize;
@@ -72,9 +69,7 @@ static int crypto_pcbc_encrypt_segment(struct blkcipher_desc *desc,
 
 
 static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
 static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
 				       struct blkcipher_walk *walk,
 				       struct blkcipher_walk *walk,
-				       struct crypto_cipher *tfm,
-				       void (*xor)(u8 *, const u8 *,
-						   unsigned int))
+				       struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_encrypt;
 		crypto_cipher_alg(tfm)->cia_encrypt;
@@ -86,10 +81,10 @@ static int crypto_pcbc_encrypt_inplace(struct blkcipher_desc *desc,
 
 
 	do {
 	do {
 		memcpy(tmpbuf, src, bsize);
 		memcpy(tmpbuf, src, bsize);
-		xor(iv, tmpbuf, bsize);
+		crypto_xor(iv, src, bsize);
 		fn(crypto_cipher_tfm(tfm), src, iv);
 		fn(crypto_cipher_tfm(tfm), src, iv);
-		memcpy(iv, src, bsize);
-		xor(iv, tmpbuf, bsize);
+		memcpy(iv, tmpbuf, bsize);
+		crypto_xor(iv, src, bsize);
 
 
 		src += bsize;
 		src += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 	} while ((nbytes -= bsize) >= bsize);
@@ -107,7 +102,6 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_cipher *child = ctx->child;
 	struct crypto_cipher *child = ctx->child;
-	void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
 	int err;
 	int err;
 
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -115,11 +109,11 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
 
 
 	while ((nbytes = walk.nbytes)) {
 	while ((nbytes = walk.nbytes)) {
 		if (walk.src.virt.addr == walk.dst.virt.addr)
 		if (walk.src.virt.addr == walk.dst.virt.addr)
-			nbytes = crypto_pcbc_encrypt_inplace(desc, &walk, child,
-							     xor);
+			nbytes = crypto_pcbc_encrypt_inplace(desc, &walk,
+							     child);
 		else
 		else
-			nbytes = crypto_pcbc_encrypt_segment(desc, &walk, child,
-							     xor);
+			nbytes = crypto_pcbc_encrypt_segment(desc, &walk,
+							     child);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 	}
 
 
@@ -128,9 +122,7 @@ static int crypto_pcbc_encrypt(struct blkcipher_desc *desc,
 
 
 static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
 static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
 				       struct blkcipher_walk *walk,
 				       struct blkcipher_walk *walk,
-				       struct crypto_cipher *tfm,
-				       void (*xor)(u8 *, const u8 *,
-						   unsigned int))
+				       struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_decrypt;
 		crypto_cipher_alg(tfm)->cia_decrypt;
@@ -142,9 +134,9 @@ static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
 
 
 	do {
 	do {
 		fn(crypto_cipher_tfm(tfm), dst, src);
 		fn(crypto_cipher_tfm(tfm), dst, src);
-		xor(dst, iv, bsize);
+		crypto_xor(dst, iv, bsize);
 		memcpy(iv, src, bsize);
 		memcpy(iv, src, bsize);
-		xor(iv, dst, bsize);
+		crypto_xor(iv, dst, bsize);
 
 
 		src += bsize;
 		src += bsize;
 		dst += bsize;
 		dst += bsize;
@@ -157,9 +149,7 @@ static int crypto_pcbc_decrypt_segment(struct blkcipher_desc *desc,
 
 
 static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
 static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
 				       struct blkcipher_walk *walk,
 				       struct blkcipher_walk *walk,
-				       struct crypto_cipher *tfm,
-				       void (*xor)(u8 *, const u8 *,
-						   unsigned int))
+				       struct crypto_cipher *tfm)
 {
 {
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
 		crypto_cipher_alg(tfm)->cia_decrypt;
 		crypto_cipher_alg(tfm)->cia_decrypt;
@@ -172,9 +162,9 @@ static int crypto_pcbc_decrypt_inplace(struct blkcipher_desc *desc,
 	do {
 	do {
 		memcpy(tmpbuf, src, bsize);
 		memcpy(tmpbuf, src, bsize);
 		fn(crypto_cipher_tfm(tfm), src, src);
 		fn(crypto_cipher_tfm(tfm), src, src);
-		xor(src, iv, bsize);
+		crypto_xor(src, iv, bsize);
 		memcpy(iv, tmpbuf, bsize);
 		memcpy(iv, tmpbuf, bsize);
-		xor(iv, src, bsize);
+		crypto_xor(iv, src, bsize);
 
 
 		src += bsize;
 		src += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 	} while ((nbytes -= bsize) >= bsize);
@@ -192,7 +182,6 @@ static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_blkcipher *tfm = desc->tfm;
 	struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_pcbc_ctx *ctx = crypto_blkcipher_ctx(tfm);
 	struct crypto_cipher *child = ctx->child;
 	struct crypto_cipher *child = ctx->child;
-	void (*xor)(u8 *, const u8 *, unsigned int bs) = ctx->xor;
 	int err;
 	int err;
 
 
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
@@ -200,48 +189,17 @@ static int crypto_pcbc_decrypt(struct blkcipher_desc *desc,
 
 
 	while ((nbytes = walk.nbytes)) {
 	while ((nbytes = walk.nbytes)) {
 		if (walk.src.virt.addr == walk.dst.virt.addr)
 		if (walk.src.virt.addr == walk.dst.virt.addr)
-			nbytes = crypto_pcbc_decrypt_inplace(desc, &walk, child,
-							     xor);
+			nbytes = crypto_pcbc_decrypt_inplace(desc, &walk,
+							     child);
 		else
 		else
-			nbytes = crypto_pcbc_decrypt_segment(desc, &walk, child,
-							     xor);
+			nbytes = crypto_pcbc_decrypt_segment(desc, &walk,
+							     child);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 	}
 
 
 	return err;
 	return err;
 }
 }
 
 
-static void xor_byte(u8 *a, const u8 *b, unsigned int bs)
-{
-	do {
-		*a++ ^= *b++;
-	} while (--bs);
-}
-
-static void xor_quad(u8 *dst, const u8 *src, unsigned int bs)
-{
-	u32 *a = (u32 *)dst;
-	u32 *b = (u32 *)src;
-
-	do {
-		*a++ ^= *b++;
-	} while ((bs -= 4));
-}
-
-static void xor_64(u8 *a, const u8 *b, unsigned int bs)
-{
-	((u32 *)a)[0] ^= ((u32 *)b)[0];
-	((u32 *)a)[1] ^= ((u32 *)b)[1];
-}
-
-static void xor_128(u8 *a, const u8 *b, unsigned int bs)
-{
-	((u32 *)a)[0] ^= ((u32 *)b)[0];
-	((u32 *)a)[1] ^= ((u32 *)b)[1];
-	((u32 *)a)[2] ^= ((u32 *)b)[2];
-	((u32 *)a)[3] ^= ((u32 *)b)[3];
-}
-
 static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
 static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
 {
 {
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
@@ -249,22 +207,6 @@ static int crypto_pcbc_init_tfm(struct crypto_tfm *tfm)
 	struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypto_pcbc_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct crypto_cipher *cipher;
 	struct crypto_cipher *cipher;
 
 
-	switch (crypto_tfm_alg_blocksize(tfm)) {
-	case 8:
-		ctx->xor = xor_64;
-		break;
-
-	case 16:
-		ctx->xor = xor_128;
-		break;
-
-	default:
-		if (crypto_tfm_alg_blocksize(tfm) % 4)
-			ctx->xor = xor_byte;
-		else
-			ctx->xor = xor_quad;
-	}
-
 	cipher = crypto_spawn_cipher(spawn);
 	cipher = crypto_spawn_cipher(spawn);
 	if (IS_ERR(cipher))
 	if (IS_ERR(cipher))
 		return PTR_ERR(cipher);
 		return PTR_ERR(cipher);
@@ -304,8 +246,9 @@ static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
 	inst->alg.cra_alignmask = alg->cra_alignmask;
 	inst->alg.cra_alignmask = alg->cra_alignmask;
 	inst->alg.cra_type = &crypto_blkcipher_type;
 	inst->alg.cra_type = &crypto_blkcipher_type;
 
 
-	if (!(alg->cra_blocksize % 4))
-		inst->alg.cra_alignmask |= 3;
+	/* We access the data as u32s when xoring. */
+	inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+
 	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
 	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
 	inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
 	inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
 	inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
 	inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize;

+ 255 - 0
crypto/salsa20_generic.c

@@ -0,0 +1,255 @@
+/*
+ * Salsa20: Salsa20 stream cipher algorithm
+ *
+ * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com>
+ *
+ * Derived from:
+ * - salsa20.c: Public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
+ *
+ * Salsa20 is a stream cipher candidate in eSTREAM, the ECRYPT Stream
+ * Cipher Project. It is designed by Daniel J. Bernstein <djb@cr.yp.to>.
+ * More information about eSTREAM and Salsa20 can be found here:
+ *   http://www.ecrypt.eu.org/stream/
+ *   http://cr.yp.to/snuffle.html
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <linux/types.h>
+#include <crypto/algapi.h>
+#include <asm/byteorder.h>
+
+#define SALSA20_IV_SIZE        8U
+#define SALSA20_MIN_KEY_SIZE  16U
+#define SALSA20_MAX_KEY_SIZE  32U
+
+/*
+ * Start of code taken from D. J. Bernstein's reference implementation.
+ * With some modifications and optimizations made to suit our needs.
+ */
+
+/*
+salsa20-ref.c version 20051118
+D. J. Bernstein
+Public domain.
+*/
+
+#define ROTATE(v,n) (((v) << (n)) | ((v) >> (32 - (n))))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+#define U32TO8_LITTLE(p, v) \
+	{ (p)[0] = (v >>  0) & 0xff; (p)[1] = (v >>  8) & 0xff; \
+	  (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; }
+#define U8TO32_LITTLE(p)   \
+	(((u32)((p)[0])      ) | ((u32)((p)[1]) <<  8) | \
+	 ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24)   )
+
+struct salsa20_ctx
+{
+	u32 input[16];
+};
+
+static void salsa20_wordtobyte(u8 output[64], const u32 input[16])
+{
+	u32 x[16];
+	int i;
+
+	memcpy(x, input, sizeof(x));
+	for (i = 20; i > 0; i -= 2) {
+		x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7));
+		x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9));
+		x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13));
+		x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18));
+		x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7));
+		x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9));
+		x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13));
+		x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18));
+		x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7));
+		x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9));
+		x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13));
+		x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18));
+		x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7));
+		x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9));
+		x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13));
+		x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18));
+		x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7));
+		x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9));
+		x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13));
+		x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18));
+		x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7));
+		x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9));
+		x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13));
+		x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18));
+		x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7));
+		x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9));
+		x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13));
+		x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18));
+		x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7));
+		x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9));
+		x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13));
+		x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18));
+	}
+	for (i = 0; i < 16; ++i)
+		x[i] = PLUS(x[i],input[i]);
+	for (i = 0; i < 16; ++i)
+		U32TO8_LITTLE(output + 4 * i,x[i]);
+}
+
+static const char sigma[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+static void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k, u32 kbytes)
+{
+	const char *constants;
+
+	ctx->input[1] = U8TO32_LITTLE(k + 0);
+	ctx->input[2] = U8TO32_LITTLE(k + 4);
+	ctx->input[3] = U8TO32_LITTLE(k + 8);
+	ctx->input[4] = U8TO32_LITTLE(k + 12);
+	if (kbytes == 32) { /* recommended */
+		k += 16;
+		constants = sigma;
+	} else { /* kbytes == 16 */
+		constants = tau;
+	}
+	ctx->input[11] = U8TO32_LITTLE(k + 0);
+	ctx->input[12] = U8TO32_LITTLE(k + 4);
+	ctx->input[13] = U8TO32_LITTLE(k + 8);
+	ctx->input[14] = U8TO32_LITTLE(k + 12);
+	ctx->input[0] = U8TO32_LITTLE(constants + 0);
+	ctx->input[5] = U8TO32_LITTLE(constants + 4);
+	ctx->input[10] = U8TO32_LITTLE(constants + 8);
+	ctx->input[15] = U8TO32_LITTLE(constants + 12);
+}
+
+static void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv)
+{
+	ctx->input[6] = U8TO32_LITTLE(iv + 0);
+	ctx->input[7] = U8TO32_LITTLE(iv + 4);
+	ctx->input[8] = 0;
+	ctx->input[9] = 0;
+}
+
+static void salsa20_encrypt_bytes(struct salsa20_ctx *ctx, u8 *dst,
+				  const u8 *src, unsigned int bytes)
+{
+	u8 buf[64];
+
+	if (dst != src)
+		memcpy(dst, src, bytes);
+
+	while (bytes) {
+		salsa20_wordtobyte(buf, ctx->input);
+
+		ctx->input[8] = PLUSONE(ctx->input[8]);
+		if (!ctx->input[8])
+			ctx->input[9] = PLUSONE(ctx->input[9]);
+
+		if (bytes <= 64) {
+			crypto_xor(dst, buf, bytes);
+			return;
+		}
+
+		crypto_xor(dst, buf, 64);
+		bytes -= 64;
+		dst += 64;
+	}
+}
+
+/*
+ * End of code taken from D. J. Bernstein's reference implementation.
+ */
+
+static int setkey(struct crypto_tfm *tfm, const u8 *key,
+		  unsigned int keysize)
+{
+	struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm);
+	salsa20_keysetup(ctx, key, keysize);
+	return 0;
+}
+
+static int encrypt(struct blkcipher_desc *desc,
+		   struct scatterlist *dst, struct scatterlist *src,
+		   unsigned int nbytes)
+{
+	struct blkcipher_walk walk;
+	struct crypto_blkcipher *tfm = desc->tfm;
+	struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm);
+	int err;
+
+	blkcipher_walk_init(&walk, dst, src, nbytes);
+	err = blkcipher_walk_virt_block(desc, &walk, 64);
+
+	salsa20_ivsetup(ctx, walk.iv);
+
+	if (likely(walk.nbytes == nbytes))
+	{
+		salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
+				      walk.src.virt.addr, nbytes);
+		return blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	while (walk.nbytes >= 64) {
+		salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
+				      walk.src.virt.addr,
+				      walk.nbytes - (walk.nbytes % 64));
+		err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64);
+	}
+
+	if (walk.nbytes) {
+		salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
+				      walk.src.virt.addr, walk.nbytes);
+		err = blkcipher_walk_done(desc, &walk, 0);
+	}
+
+	return err;
+}
+
+static struct crypto_alg alg = {
+	.cra_name           =   "salsa20",
+	.cra_driver_name    =   "salsa20-generic",
+	.cra_priority       =   100,
+	.cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_type           =   &crypto_blkcipher_type,
+	.cra_blocksize      =   1,
+	.cra_ctxsize        =   sizeof(struct salsa20_ctx),
+	.cra_alignmask      =	3,
+	.cra_module         =   THIS_MODULE,
+	.cra_list           =   LIST_HEAD_INIT(alg.cra_list),
+	.cra_u              =   {
+		.blkcipher = {
+			.setkey         =   setkey,
+			.encrypt        =   encrypt,
+			.decrypt        =   encrypt,
+			.min_keysize    =   SALSA20_MIN_KEY_SIZE,
+			.max_keysize    =   SALSA20_MAX_KEY_SIZE,
+			.ivsize         =   SALSA20_IV_SIZE,
+		}
+	}
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm");
+MODULE_ALIAS("salsa20");

+ 6 - 4
crypto/scatterwalk.c

@@ -13,6 +13,8 @@
  * any later version.
  * any later version.
  *
  *
  */
  */
+
+#include <crypto/scatterwalk.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/module.h>
@@ -20,9 +22,6 @@
 #include <linux/highmem.h>
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 
 
-#include "internal.h"
-#include "scatterwalk.h"
-
 static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
 static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out)
 {
 {
 	void *src = out ? buf : sgdata;
 	void *src = out ? buf : sgdata;
@@ -106,6 +105,9 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
 	struct scatter_walk walk;
 	struct scatter_walk walk;
 	unsigned int offset = 0;
 	unsigned int offset = 0;
 
 
+	if (!nbytes)
+		return;
+
 	for (;;) {
 	for (;;) {
 		scatterwalk_start(&walk, sg);
 		scatterwalk_start(&walk, sg);
 
 
@@ -113,7 +115,7 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
 			break;
 			break;
 
 
 		offset += sg->length;
 		offset += sg->length;
-		sg = sg_next(sg);
+		sg = scatterwalk_sg_next(sg);
 	}
 	}
 
 
 	scatterwalk_advance(&walk, start - offset);
 	scatterwalk_advance(&walk, start - offset);

+ 345 - 0
crypto/seqiv.c

@@ -0,0 +1,345 @@
+/*
+ * seqiv: Sequence Number IV Generator
+ *
+ * This generator generates an IV based on a sequence number by xoring it
+ * with a salt.  This algorithm is mainly useful for CTR and similar modes.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+struct seqiv_ctx {
+	spinlock_t lock;
+	u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
+};
+
+static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err)
+{
+	struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+	struct crypto_ablkcipher *geniv;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	if (err)
+		goto out;
+
+	geniv = skcipher_givcrypt_reqtfm(req);
+	memcpy(req->creq.info, subreq->info, crypto_ablkcipher_ivsize(geniv));
+
+out:
+	kfree(subreq->info);
+}
+
+static void seqiv_complete(struct crypto_async_request *base, int err)
+{
+	struct skcipher_givcrypt_request *req = base->data;
+
+	seqiv_complete2(req, err);
+	skcipher_givcrypt_complete(req, err);
+}
+
+static void seqiv_aead_complete2(struct aead_givcrypt_request *req, int err)
+{
+	struct aead_request *subreq = aead_givcrypt_reqctx(req);
+	struct crypto_aead *geniv;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	if (err)
+		goto out;
+
+	geniv = aead_givcrypt_reqtfm(req);
+	memcpy(req->areq.iv, subreq->iv, crypto_aead_ivsize(geniv));
+
+out:
+	kfree(subreq->iv);
+}
+
+static void seqiv_aead_complete(struct crypto_async_request *base, int err)
+{
+	struct aead_givcrypt_request *req = base->data;
+
+	seqiv_aead_complete2(req, err);
+	aead_givcrypt_complete(req, err);
+}
+
+static void seqiv_geniv(struct seqiv_ctx *ctx, u8 *info, u64 seq,
+			unsigned int ivsize)
+{
+	unsigned int len = ivsize;
+
+	if (ivsize > sizeof(u64)) {
+		memset(info, 0, ivsize - sizeof(u64));
+		len = sizeof(u64);
+	}
+	seq = cpu_to_be64(seq);
+	memcpy(info + ivsize - len, &seq, len);
+	crypto_xor(info, ctx->salt, ivsize);
+}
+
+static int seqiv_givencrypt(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+	struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
+	crypto_completion_t complete;
+	void *data;
+	u8 *info;
+	unsigned int ivsize;
+	int err;
+
+	ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
+
+	complete = req->creq.base.complete;
+	data = req->creq.base.data;
+	info = req->creq.info;
+
+	ivsize = crypto_ablkcipher_ivsize(geniv);
+
+	if (unlikely(!IS_ALIGNED((unsigned long)info,
+				 crypto_ablkcipher_alignmask(geniv) + 1))) {
+		info = kmalloc(ivsize, req->creq.base.flags &
+				       CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+								  GFP_ATOMIC);
+		if (!info)
+			return -ENOMEM;
+
+		complete = seqiv_complete;
+		data = req;
+	}
+
+	ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
+					data);
+	ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
+				     req->creq.nbytes, info);
+
+	seqiv_geniv(ctx, info, req->seq, ivsize);
+	memcpy(req->giv, info, ivsize);
+
+	err = crypto_ablkcipher_encrypt(subreq);
+	if (unlikely(info != req->creq.info))
+		seqiv_complete2(req, err);
+	return err;
+}
+
+static int seqiv_aead_givencrypt(struct aead_givcrypt_request *req)
+{
+	struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
+	struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+	struct aead_request *areq = &req->areq;
+	struct aead_request *subreq = aead_givcrypt_reqctx(req);
+	crypto_completion_t complete;
+	void *data;
+	u8 *info;
+	unsigned int ivsize;
+	int err;
+
+	aead_request_set_tfm(subreq, aead_geniv_base(geniv));
+
+	complete = areq->base.complete;
+	data = areq->base.data;
+	info = areq->iv;
+
+	ivsize = crypto_aead_ivsize(geniv);
+
+	if (unlikely(!IS_ALIGNED((unsigned long)info,
+				 crypto_aead_alignmask(geniv) + 1))) {
+		info = kmalloc(ivsize, areq->base.flags &
+				       CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+								  GFP_ATOMIC);
+		if (!info)
+			return -ENOMEM;
+
+		complete = seqiv_aead_complete;
+		data = req;
+	}
+
+	aead_request_set_callback(subreq, areq->base.flags, complete, data);
+	aead_request_set_crypt(subreq, areq->src, areq->dst, areq->cryptlen,
+			       info);
+	aead_request_set_assoc(subreq, areq->assoc, areq->assoclen);
+
+	seqiv_geniv(ctx, info, req->seq, ivsize);
+	memcpy(req->giv, info, ivsize);
+
+	err = crypto_aead_encrypt(subreq);
+	if (unlikely(info != areq->iv))
+		seqiv_aead_complete2(req, err);
+	return err;
+}
+
+static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+{
+	struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
+	struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+	spin_lock_bh(&ctx->lock);
+	if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
+		goto unlock;
+
+	crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
+	get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
+
+unlock:
+	spin_unlock_bh(&ctx->lock);
+
+	return seqiv_givencrypt(req);
+}
+
+static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req)
+{
+	struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
+	struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+
+	spin_lock_bh(&ctx->lock);
+	if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
+		goto unlock;
+
+	crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
+	get_random_bytes(ctx->salt, crypto_aead_ivsize(geniv));
+
+unlock:
+	spin_unlock_bh(&ctx->lock);
+
+	return seqiv_aead_givencrypt(req);
+}
+
+static int seqiv_init(struct crypto_tfm *tfm)
+{
+	struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
+	struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+
+	spin_lock_init(&ctx->lock);
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
+
+	return skcipher_geniv_init(tfm);
+}
+
+static int seqiv_aead_init(struct crypto_tfm *tfm)
+{
+	struct crypto_aead *geniv = __crypto_aead_cast(tfm);
+	struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+
+	spin_lock_init(&ctx->lock);
+
+	tfm->crt_aead.reqsize = sizeof(struct aead_request);
+
+	return aead_geniv_init(tfm);
+}
+
+static struct crypto_template seqiv_tmpl;
+
+static struct crypto_instance *seqiv_ablkcipher_alloc(struct rtattr **tb)
+{
+	struct crypto_instance *inst;
+
+	inst = skcipher_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
+
+	if (IS_ERR(inst))
+		goto out;
+
+	inst->alg.cra_ablkcipher.givencrypt = seqiv_givencrypt_first;
+
+	inst->alg.cra_init = seqiv_init;
+	inst->alg.cra_exit = skcipher_geniv_exit;
+
+	inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+
+out:
+	return inst;
+}
+
+static struct crypto_instance *seqiv_aead_alloc(struct rtattr **tb)
+{
+	struct crypto_instance *inst;
+
+	inst = aead_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
+
+	if (IS_ERR(inst))
+		goto out;
+
+	inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first;
+
+	inst->alg.cra_init = seqiv_aead_init;
+	inst->alg.cra_exit = aead_geniv_exit;
+
+	inst->alg.cra_ctxsize = inst->alg.cra_aead.ivsize;
+
+out:
+	return inst;
+}
+
+static struct crypto_instance *seqiv_alloc(struct rtattr **tb)
+{
+	struct crypto_attr_type *algt;
+	struct crypto_instance *inst;
+	int err;
+
+	algt = crypto_get_attr_type(tb);
+	err = PTR_ERR(algt);
+	if (IS_ERR(algt))
+		return ERR_PTR(err);
+
+	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
+		inst = seqiv_ablkcipher_alloc(tb);
+	else
+		inst = seqiv_aead_alloc(tb);
+
+	if (IS_ERR(inst))
+		goto out;
+
+	inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+	inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);
+
+out:
+	return inst;
+}
+
+static void seqiv_free(struct crypto_instance *inst)
+{
+	if ((inst->alg.cra_flags ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
+		skcipher_geniv_free(inst);
+	else
+		aead_geniv_free(inst);
+}
+
+static struct crypto_template seqiv_tmpl = {
+	.name = "seqiv",
+	.alloc = seqiv_alloc,
+	.free = seqiv_free,
+	.module = THIS_MODULE,
+};
+
+static int __init seqiv_module_init(void)
+{
+	return crypto_register_template(&seqiv_tmpl);
+}
+
+static void __exit seqiv_module_exit(void)
+{
+	crypto_unregister_template(&seqiv_tmpl);
+}
+
+module_init(seqiv_module_init);
+module_exit(seqiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Sequence Number IV Generator");

+ 64 - 8
crypto/sha256_generic.c

@@ -9,6 +9,7 @@
  * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
  * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
  * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
  * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -218,6 +219,22 @@ static void sha256_transform(u32 *state, const u8 *input)
 	memset(W, 0, 64 * sizeof(u32));
 	memset(W, 0, 64 * sizeof(u32));
 }
 }
 
 
+
+static void sha224_init(struct crypto_tfm *tfm)
+{
+	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+	sctx->state[0] = SHA224_H0;
+	sctx->state[1] = SHA224_H1;
+	sctx->state[2] = SHA224_H2;
+	sctx->state[3] = SHA224_H3;
+	sctx->state[4] = SHA224_H4;
+	sctx->state[5] = SHA224_H5;
+	sctx->state[6] = SHA224_H6;
+	sctx->state[7] = SHA224_H7;
+	sctx->count[0] = 0;
+	sctx->count[1] = 0;
+}
+
 static void sha256_init(struct crypto_tfm *tfm)
 static void sha256_init(struct crypto_tfm *tfm)
 {
 {
 	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
@@ -294,8 +311,17 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out)
 	memset(sctx, 0, sizeof(*sctx));
 	memset(sctx, 0, sizeof(*sctx));
 }
 }
 
 
+static void sha224_final(struct crypto_tfm *tfm, u8 *hash)
+{
+	u8 D[SHA256_DIGEST_SIZE];
+
+	sha256_final(tfm, D);
+
+	memcpy(hash, D, SHA224_DIGEST_SIZE);
+	memset(D, 0, SHA256_DIGEST_SIZE);
+}
 
 
-static struct crypto_alg alg = {
+static struct crypto_alg sha256 = {
 	.cra_name	=	"sha256",
 	.cra_name	=	"sha256",
 	.cra_driver_name=	"sha256-generic",
 	.cra_driver_name=	"sha256-generic",
 	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
 	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
@@ -303,28 +329,58 @@ static struct crypto_alg alg = {
 	.cra_ctxsize	=	sizeof(struct sha256_ctx),
 	.cra_ctxsize	=	sizeof(struct sha256_ctx),
 	.cra_module	=	THIS_MODULE,
 	.cra_module	=	THIS_MODULE,
 	.cra_alignmask	=	3,
 	.cra_alignmask	=	3,
-	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+	.cra_list	=	LIST_HEAD_INIT(sha256.cra_list),
 	.cra_u		=	{ .digest = {
 	.cra_u		=	{ .digest = {
 	.dia_digestsize	=	SHA256_DIGEST_SIZE,
 	.dia_digestsize	=	SHA256_DIGEST_SIZE,
-	.dia_init   	= 	sha256_init,
-	.dia_update 	=	sha256_update,
-	.dia_final  	=	sha256_final } }
+	.dia_init	=	sha256_init,
+	.dia_update	=	sha256_update,
+	.dia_final	=	sha256_final } }
+};
+
+static struct crypto_alg sha224 = {
+	.cra_name	= "sha224",
+	.cra_driver_name = "sha224-generic",
+	.cra_flags	= CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	= SHA224_BLOCK_SIZE,
+	.cra_ctxsize	= sizeof(struct sha256_ctx),
+	.cra_module	= THIS_MODULE,
+	.cra_alignmask	= 3,
+	.cra_list	= LIST_HEAD_INIT(sha224.cra_list),
+	.cra_u		= { .digest = {
+	.dia_digestsize = SHA224_DIGEST_SIZE,
+	.dia_init	= sha224_init,
+	.dia_update	= sha256_update,
+	.dia_final	= sha224_final } }
 };
 };
 
 
 static int __init init(void)
 static int __init init(void)
 {
 {
-	return crypto_register_alg(&alg);
+	int ret = 0;
+
+	ret = crypto_register_alg(&sha224);
+
+	if (ret < 0)
+		return ret;
+
+	ret = crypto_register_alg(&sha256);
+
+	if (ret < 0)
+		crypto_unregister_alg(&sha224);
+
+	return ret;
 }
 }
 
 
 static void __exit fini(void)
 static void __exit fini(void)
 {
 {
-	crypto_unregister_alg(&alg);
+	crypto_unregister_alg(&sha224);
+	crypto_unregister_alg(&sha256);
 }
 }
 
 
 module_init(init);
 module_init(init);
 module_exit(fini);
 module_exit(fini);
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm");
+MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm");
 
 
+MODULE_ALIAS("sha224");
 MODULE_ALIAS("sha256");
 MODULE_ALIAS("sha256");

+ 384 - 65
crypto/tcrypt.c

@@ -6,12 +6,16 @@
  *
  *
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
  * 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
  * 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
  * 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)
  * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  * any later version.
  *
  *
+ * 2007-11-13 Added GCM tests
+ * 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
  * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
  * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
  * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
  * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt
  * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt
@@ -71,22 +75,23 @@ static unsigned int sec;
 
 
 static int mode;
 static int mode;
 static char *xbuf;
 static char *xbuf;
+static char *axbuf;
 static char *tvmem;
 static char *tvmem;
 
 
 static char *check[] = {
 static char *check[] = {
-	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
-	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
+	"des", "md5", "des3_ede", "rot13", "sha1", "sha224", "sha256",
+	"blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes",
+	"cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
 	"arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
 	"arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
 	"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
 	"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
-	"camellia", "seed", NULL
+	"camellia", "seed", "salsa20", "lzo", NULL
 };
 };
 
 
 static void hexdump(unsigned char *buf, unsigned int len)
 static void hexdump(unsigned char *buf, unsigned int len)
 {
 {
-	while (len--)
-		printk("%02x", *buf++);
-
-	printk("\n");
+	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+			16, 1,
+			buf, len, false);
 }
 }
 
 
 static void tcrypt_complete(struct crypto_async_request *req, int err)
 static void tcrypt_complete(struct crypto_async_request *req, int err)
@@ -215,6 +220,238 @@ out:
 	crypto_free_hash(tfm);
 	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;
+	unsigned int authsize;
+
+	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;
+			}
+
+			authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen);
+			ret = crypto_aead_setauthsize(tfm, authsize);
+			if (ret) {
+				printk(KERN_INFO
+				       "failed to set authsize = %u\n",
+				       authsize);
+				goto out;
+			}
+
+			sg_init_one(&sg[0], aead_tv[i].input,
+				    aead_tv[i].ilen + (enc ? authsize : 0));
+
+			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);
+
+			ret = enc ?
+				crypto_aead_encrypt(req) :
+				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 "enc/dec: %s\n",
+			       memcmp(q, aead_tv[i].result,
+				      aead_tv[i].rlen) ? "fail" : "pass");
+		}
+	}
+
+	printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
+	memset(xbuf, 0, XBUFSIZE);
+	memset(axbuf, 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]);
+			}
+
+			authsize = abs(aead_tv[i].rlen - aead_tv[i].ilen);
+			ret = crypto_aead_setauthsize(tfm, authsize);
+			if (ret) {
+				printk(KERN_INFO
+				       "failed to set authsize = %u\n",
+				       authsize);
+				goto out;
+			}
+
+			if (enc)
+				sg[k - 1].length += authsize;
+
+			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);
+
+			ret = enc ?
+				crypto_aead_encrypt(req) :
+				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] -
+					      (k < aead_tv[i].np - 1 || enc ?
+					       0 : authsize)) ?
+				       "fail" : "pass");
+
+				temp += aead_tv[i].tap[k];
+			}
+		}
+	}
+
+out:
+	crypto_free_aead(tfm);
+	aead_request_free(req);
+}
+
 static void test_cipher(char *algo, int enc,
 static void test_cipher(char *algo, int enc,
 			struct cipher_testvec *template, unsigned int tcount)
 			struct cipher_testvec *template, unsigned int tcount)
 {
 {
@@ -237,15 +474,11 @@ static void test_cipher(char *algo, int enc,
 	printk("\ntesting %s %s\n", algo, e);
 	printk("\ntesting %s %s\n", algo, e);
 
 
 	tsize = sizeof (struct cipher_testvec);
 	tsize = sizeof (struct cipher_testvec);
-	tsize *= tcount;
-
 	if (tsize > TVMEMSIZE) {
 	if (tsize > TVMEMSIZE) {
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		       TVMEMSIZE);
 		       TVMEMSIZE);
 		return;
 		return;
 	}
 	}
-
-	memcpy(tvmem, template, tsize);
 	cipher_tv = (void *)tvmem;
 	cipher_tv = (void *)tvmem;
 
 
 	init_completion(&result.completion);
 	init_completion(&result.completion);
@@ -269,33 +502,34 @@ static void test_cipher(char *algo, int enc,
 
 
 	j = 0;
 	j = 0;
 	for (i = 0; i < tcount; i++) {
 	for (i = 0; i < tcount; i++) {
-		if (!(cipher_tv[i].np)) {
+		memcpy(cipher_tv, &template[i], tsize);
+		if (!(cipher_tv->np)) {
 			j++;
 			j++;
 			printk("test %u (%d bit key):\n",
 			printk("test %u (%d bit key):\n",
-			j, cipher_tv[i].klen * 8);
+			j, cipher_tv->klen * 8);
 
 
 			crypto_ablkcipher_clear_flags(tfm, ~0);
 			crypto_ablkcipher_clear_flags(tfm, ~0);
-			if (cipher_tv[i].wk)
+			if (cipher_tv->wk)
 				crypto_ablkcipher_set_flags(
 				crypto_ablkcipher_set_flags(
 					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
 					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-			key = cipher_tv[i].key;
+			key = cipher_tv->key;
 
 
 			ret = crypto_ablkcipher_setkey(tfm, key,
 			ret = crypto_ablkcipher_setkey(tfm, key,
-						       cipher_tv[i].klen);
+						       cipher_tv->klen);
 			if (ret) {
 			if (ret) {
 				printk("setkey() failed flags=%x\n",
 				printk("setkey() failed flags=%x\n",
 				       crypto_ablkcipher_get_flags(tfm));
 				       crypto_ablkcipher_get_flags(tfm));
 
 
-				if (!cipher_tv[i].fail)
+				if (!cipher_tv->fail)
 					goto out;
 					goto out;
 			}
 			}
 
 
-			sg_init_one(&sg[0], cipher_tv[i].input,
-				    cipher_tv[i].ilen);
+			sg_init_one(&sg[0], cipher_tv->input,
+				    cipher_tv->ilen);
 
 
 			ablkcipher_request_set_crypt(req, sg, sg,
 			ablkcipher_request_set_crypt(req, sg, sg,
-						     cipher_tv[i].ilen,
-						     cipher_tv[i].iv);
+						     cipher_tv->ilen,
+						     cipher_tv->iv);
 
 
 			ret = enc ?
 			ret = enc ?
 				crypto_ablkcipher_encrypt(req) :
 				crypto_ablkcipher_encrypt(req) :
@@ -319,11 +553,11 @@ static void test_cipher(char *algo, int enc,
 			}
 			}
 
 
 			q = kmap(sg_page(&sg[0])) + sg[0].offset;
 			q = kmap(sg_page(&sg[0])) + sg[0].offset;
-			hexdump(q, cipher_tv[i].rlen);
+			hexdump(q, cipher_tv->rlen);
 
 
 			printk("%s\n",
 			printk("%s\n",
-			       memcmp(q, cipher_tv[i].result,
-				      cipher_tv[i].rlen) ? "fail" : "pass");
+			       memcmp(q, cipher_tv->result,
+				      cipher_tv->rlen) ? "fail" : "pass");
 		}
 		}
 	}
 	}
 
 
@@ -332,41 +566,42 @@ static void test_cipher(char *algo, int enc,
 
 
 	j = 0;
 	j = 0;
 	for (i = 0; i < tcount; i++) {
 	for (i = 0; i < tcount; i++) {
-		if (cipher_tv[i].np) {
+		memcpy(cipher_tv, &template[i], tsize);
+		if (cipher_tv->np) {
 			j++;
 			j++;
 			printk("test %u (%d bit key):\n",
 			printk("test %u (%d bit key):\n",
-			j, cipher_tv[i].klen * 8);
+			j, cipher_tv->klen * 8);
 
 
 			crypto_ablkcipher_clear_flags(tfm, ~0);
 			crypto_ablkcipher_clear_flags(tfm, ~0);
-			if (cipher_tv[i].wk)
+			if (cipher_tv->wk)
 				crypto_ablkcipher_set_flags(
 				crypto_ablkcipher_set_flags(
 					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
 					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
-			key = cipher_tv[i].key;
+			key = cipher_tv->key;
 
 
 			ret = crypto_ablkcipher_setkey(tfm, key,
 			ret = crypto_ablkcipher_setkey(tfm, key,
-						       cipher_tv[i].klen);
+						       cipher_tv->klen);
 			if (ret) {
 			if (ret) {
 				printk("setkey() failed flags=%x\n",
 				printk("setkey() failed flags=%x\n",
 				       crypto_ablkcipher_get_flags(tfm));
 				       crypto_ablkcipher_get_flags(tfm));
 
 
-				if (!cipher_tv[i].fail)
+				if (!cipher_tv->fail)
 					goto out;
 					goto out;
 			}
 			}
 
 
 			temp = 0;
 			temp = 0;
-			sg_init_table(sg, cipher_tv[i].np);
-			for (k = 0; k < cipher_tv[i].np; k++) {
+			sg_init_table(sg, cipher_tv->np);
+			for (k = 0; k < cipher_tv->np; k++) {
 				memcpy(&xbuf[IDX[k]],
 				memcpy(&xbuf[IDX[k]],
-				       cipher_tv[i].input + temp,
-				       cipher_tv[i].tap[k]);
-				temp += cipher_tv[i].tap[k];
+				       cipher_tv->input + temp,
+				       cipher_tv->tap[k]);
+				temp += cipher_tv->tap[k];
 				sg_set_buf(&sg[k], &xbuf[IDX[k]],
 				sg_set_buf(&sg[k], &xbuf[IDX[k]],
-					   cipher_tv[i].tap[k]);
+					   cipher_tv->tap[k]);
 			}
 			}
 
 
 			ablkcipher_request_set_crypt(req, sg, sg,
 			ablkcipher_request_set_crypt(req, sg, sg,
-						     cipher_tv[i].ilen,
-						     cipher_tv[i].iv);
+						     cipher_tv->ilen,
+						     cipher_tv->iv);
 
 
 			ret = enc ?
 			ret = enc ?
 				crypto_ablkcipher_encrypt(req) :
 				crypto_ablkcipher_encrypt(req) :
@@ -390,15 +625,15 @@ static void test_cipher(char *algo, int enc,
 			}
 			}
 
 
 			temp = 0;
 			temp = 0;
-			for (k = 0; k < cipher_tv[i].np; k++) {
+			for (k = 0; k < cipher_tv->np; k++) {
 				printk("page %u\n", k);
 				printk("page %u\n", k);
 				q = kmap(sg_page(&sg[k])) + sg[k].offset;
 				q = kmap(sg_page(&sg[k])) + sg[k].offset;
-				hexdump(q, cipher_tv[i].tap[k]);
+				hexdump(q, cipher_tv->tap[k]);
 				printk("%s\n",
 				printk("%s\n",
-					memcmp(q, cipher_tv[i].result + temp,
-						cipher_tv[i].tap[k]) ? "fail" :
+					memcmp(q, cipher_tv->result + temp,
+						cipher_tv->tap[k]) ? "fail" :
 					"pass");
 					"pass");
-				temp += cipher_tv[i].tap[k];
+				temp += cipher_tv->tap[k];
 			}
 			}
 		}
 		}
 	}
 	}
@@ -800,7 +1035,8 @@ out:
 	crypto_free_hash(tfm);
 	crypto_free_hash(tfm);
 }
 }
 
 
-static void test_deflate(void)
+static void test_comp(char *algo, struct comp_testvec *ctemplate,
+		       struct comp_testvec *dtemplate, int ctcount, int dtcount)
 {
 {
 	unsigned int i;
 	unsigned int i;
 	char result[COMP_BUF_SIZE];
 	char result[COMP_BUF_SIZE];
@@ -808,25 +1044,26 @@ static void test_deflate(void)
 	struct comp_testvec *tv;
 	struct comp_testvec *tv;
 	unsigned int tsize;
 	unsigned int tsize;
 
 
-	printk("\ntesting deflate compression\n");
+	printk("\ntesting %s compression\n", algo);
 
 
-	tsize = sizeof (deflate_comp_tv_template);
+	tsize = sizeof(struct comp_testvec);
+	tsize *= ctcount;
 	if (tsize > TVMEMSIZE) {
 	if (tsize > TVMEMSIZE) {
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		       TVMEMSIZE);
 		       TVMEMSIZE);
 		return;
 		return;
 	}
 	}
 
 
-	memcpy(tvmem, deflate_comp_tv_template, tsize);
+	memcpy(tvmem, ctemplate, tsize);
 	tv = (void *)tvmem;
 	tv = (void *)tvmem;
 
 
-	tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC);
+	tfm = crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(tfm)) {
 	if (IS_ERR(tfm)) {
-		printk("failed to load transform for deflate\n");
+		printk("failed to load transform for %s\n", algo);
 		return;
 		return;
 	}
 	}
 
 
-	for (i = 0; i < DEFLATE_COMP_TEST_VECTORS; i++) {
+	for (i = 0; i < ctcount; i++) {
 		int ilen, ret, dlen = COMP_BUF_SIZE;
 		int ilen, ret, dlen = COMP_BUF_SIZE;
 
 
 		printk("test %u:\n", i + 1);
 		printk("test %u:\n", i + 1);
@@ -845,19 +1082,20 @@ static void test_deflate(void)
 		       ilen, dlen);
 		       ilen, dlen);
 	}
 	}
 
 
-	printk("\ntesting deflate decompression\n");
+	printk("\ntesting %s decompression\n", algo);
 
 
-	tsize = sizeof (deflate_decomp_tv_template);
+	tsize = sizeof(struct comp_testvec);
+	tsize *= dtcount;
 	if (tsize > TVMEMSIZE) {
 	if (tsize > TVMEMSIZE) {
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		       TVMEMSIZE);
 		       TVMEMSIZE);
 		goto out;
 		goto out;
 	}
 	}
 
 
-	memcpy(tvmem, deflate_decomp_tv_template, tsize);
+	memcpy(tvmem, dtemplate, tsize);
 	tv = (void *)tvmem;
 	tv = (void *)tvmem;
 
 
-	for (i = 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) {
+	for (i = 0; i < dtcount; i++) {
 		int ilen, ret, dlen = COMP_BUF_SIZE;
 		int ilen, ret, dlen = COMP_BUF_SIZE;
 
 
 		printk("test %u:\n", i + 1);
 		printk("test %u:\n", i + 1);
@@ -918,6 +1156,8 @@ static void do_test(void)
 
 
 		test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
 		test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
 
 
+		test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
+
 		test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS);
 		test_hash("sha256", sha256_tv_template, SHA256_TEST_VECTORS);
 
 
 		//BLOWFISH
 		//BLOWFISH
@@ -969,6 +1209,18 @@ static void do_test(void)
 			    AES_XTS_ENC_TEST_VECTORS);
 			    AES_XTS_ENC_TEST_VECTORS);
 		test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
 		test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
 			    AES_XTS_DEC_TEST_VECTORS);
 			    AES_XTS_DEC_TEST_VECTORS);
+		test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template,
+			    AES_CTR_ENC_TEST_VECTORS);
+		test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template,
+			    AES_CTR_DEC_TEST_VECTORS);
+		test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template,
+			  AES_GCM_ENC_TEST_VECTORS);
+		test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template,
+			  AES_GCM_DEC_TEST_VECTORS);
+		test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template,
+			  AES_CCM_ENC_TEST_VECTORS);
+		test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template,
+			  AES_CCM_DEC_TEST_VECTORS);
 
 
 		//CAST5
 		//CAST5
 		test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
 		test_cipher("ecb(cast5)", ENCRYPT, cast5_enc_tv_template,
@@ -1057,12 +1309,18 @@ static void do_test(void)
 		test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
 		test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS);
 		test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
 		test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS);
 		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
 		test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
-		test_deflate();
+		test_comp("deflate", deflate_comp_tv_template,
+			  deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS,
+			  DEFLATE_DECOMP_TEST_VECTORS);
+		test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template,
+			  LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS);
 		test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
 		test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS);
 		test_hash("hmac(md5)", hmac_md5_tv_template,
 		test_hash("hmac(md5)", hmac_md5_tv_template,
 			  HMAC_MD5_TEST_VECTORS);
 			  HMAC_MD5_TEST_VECTORS);
 		test_hash("hmac(sha1)", hmac_sha1_tv_template,
 		test_hash("hmac(sha1)", hmac_sha1_tv_template,
 			  HMAC_SHA1_TEST_VECTORS);
 			  HMAC_SHA1_TEST_VECTORS);
+		test_hash("hmac(sha224)", hmac_sha224_tv_template,
+			  HMAC_SHA224_TEST_VECTORS);
 		test_hash("hmac(sha256)", hmac_sha256_tv_template,
 		test_hash("hmac(sha256)", hmac_sha256_tv_template,
 			  HMAC_SHA256_TEST_VECTORS);
 			  HMAC_SHA256_TEST_VECTORS);
 		test_hash("hmac(sha384)", hmac_sha384_tv_template,
 		test_hash("hmac(sha384)", hmac_sha384_tv_template,
@@ -1156,6 +1414,10 @@ static void do_test(void)
 			    AES_XTS_ENC_TEST_VECTORS);
 			    AES_XTS_ENC_TEST_VECTORS);
 		test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
 		test_cipher("xts(aes)", DECRYPT, aes_xts_dec_tv_template,
 			    AES_XTS_DEC_TEST_VECTORS);
 			    AES_XTS_DEC_TEST_VECTORS);
+		test_cipher("rfc3686(ctr(aes))", ENCRYPT, aes_ctr_enc_tv_template,
+			    AES_CTR_ENC_TEST_VECTORS);
+		test_cipher("rfc3686(ctr(aes))", DECRYPT, aes_ctr_dec_tv_template,
+			    AES_CTR_DEC_TEST_VECTORS);
 		break;
 		break;
 
 
 	case 11:
 	case 11:
@@ -1167,7 +1429,9 @@ static void do_test(void)
 		break;
 		break;
 
 
 	case 13:
 	case 13:
-		test_deflate();
+		test_comp("deflate", deflate_comp_tv_template,
+			  deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS,
+			  DEFLATE_DECOMP_TEST_VECTORS);
 		break;
 		break;
 
 
 	case 14:
 	case 14:
@@ -1291,6 +1555,34 @@ static void do_test(void)
 			    camellia_cbc_dec_tv_template,
 			    camellia_cbc_dec_tv_template,
 			    CAMELLIA_CBC_DEC_TEST_VECTORS);
 			    CAMELLIA_CBC_DEC_TEST_VECTORS);
 		break;
 		break;
+	case 33:
+		test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
+		break;
+
+	case 34:
+		test_cipher("salsa20", ENCRYPT,
+			    salsa20_stream_enc_tv_template,
+			    SALSA20_STREAM_ENC_TEST_VECTORS);
+		break;
+
+	case 35:
+		test_aead("gcm(aes)", ENCRYPT, aes_gcm_enc_tv_template,
+			  AES_GCM_ENC_TEST_VECTORS);
+		test_aead("gcm(aes)", DECRYPT, aes_gcm_dec_tv_template,
+			  AES_GCM_DEC_TEST_VECTORS);
+		break;
+
+	case 36:
+		test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template,
+			  LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS);
+		break;
+
+	case 37:
+		test_aead("ccm(aes)", ENCRYPT, aes_ccm_enc_tv_template,
+			  AES_CCM_ENC_TEST_VECTORS);
+		test_aead("ccm(aes)", DECRYPT, aes_ccm_dec_tv_template,
+			  AES_CCM_DEC_TEST_VECTORS);
+		break;
 
 
 	case 100:
 	case 100:
 		test_hash("hmac(md5)", hmac_md5_tv_template,
 		test_hash("hmac(md5)", hmac_md5_tv_template,
@@ -1317,6 +1609,15 @@ static void do_test(void)
 			  HMAC_SHA512_TEST_VECTORS);
 			  HMAC_SHA512_TEST_VECTORS);
 		break;
 		break;
 
 
+	case 105:
+		test_hash("hmac(sha224)", hmac_sha224_tv_template,
+			  HMAC_SHA224_TEST_VECTORS);
+		break;
+
+	case 106:
+		test_hash("xcbc(aes)", aes_xcbc128_tv_template,
+			  XCBC_AES_TEST_VECTORS);
+		break;
 
 
 	case 200:
 	case 200:
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
@@ -1400,6 +1701,11 @@ static void do_test(void)
 				camellia_speed_template);
 				camellia_speed_template);
 		break;
 		break;
 
 
+	case 206:
+		test_cipher_speed("salsa20", ENCRYPT, sec, NULL, 0,
+				  salsa20_speed_template);
+		break;
+
 	case 300:
 	case 300:
 		/* fall through */
 		/* fall through */
 
 
@@ -1451,6 +1757,10 @@ static void do_test(void)
 		test_hash_speed("tgr192", sec, generic_hash_speed_template);
 		test_hash_speed("tgr192", sec, generic_hash_speed_template);
 		if (mode > 300 && mode < 400) break;
 		if (mode > 300 && mode < 400) break;
 
 
+	case 313:
+		test_hash_speed("sha224", sec, generic_hash_speed_template);
+		if (mode > 300 && mode < 400) break;
+
 	case 399:
 	case 399:
 		break;
 		break;
 
 
@@ -1467,20 +1777,21 @@ static void do_test(void)
 
 
 static int __init init(void)
 static int __init init(void)
 {
 {
+	int err = -ENOMEM;
+
 	tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL);
 	tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL);
 	if (tvmem == NULL)
 	if (tvmem == NULL)
-		return -ENOMEM;
+		return err;
 
 
 	xbuf = kmalloc(XBUFSIZE, GFP_KERNEL);
 	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
 	/* We intentionaly return -EAGAIN to prevent keeping
 	 * the module. It does all its work from init()
 	 * the module. It does all its work from init()
@@ -1488,7 +1799,15 @@ static int __init init(void)
 	 * => we don't need it in the memory, do we?
 	 * => we don't need it in the memory, do we?
 	 *                                        -- mludvig
 	 *                                        -- mludvig
 	 */
 	 */
-	return -EAGAIN;
+	err = -EAGAIN;
+
+	kfree(axbuf);
+ err_free_xbuf:
+	kfree(xbuf);
+ err_free_tv:
+	kfree(tvmem);
+
+	return err;
 }
 }
 
 
 /*
 /*

File diff suppressed because it is too large
+ 2110 - 2
crypto/tcrypt.h


+ 30 - 66
crypto/twofish_common.c

@@ -655,84 +655,48 @@ int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
 			CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
 			CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
 		}
 		}
 
 
-		/* Calculate whitening and round subkeys.  The constants are
-		 * indices of subkeys, preprocessed through q0 and q1. */
-		CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
-		CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
-		CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
-		CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
-		CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
-		CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
-		CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
-		CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
-		CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
-		CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
-		CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
-		CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
-		CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
-		CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
-		CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
-		CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
-		CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
-		CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
-		CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
-		CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+		/* CALC_K256/CALC_K192/CALC_K loops were unrolled.
+		 * Unrolling produced x2.5 more code (+18k on i386),
+		 * and speeded up key setup by 7%:
+		 * unrolled: twofish_setkey/sec: 41128
+		 *     loop: twofish_setkey/sec: 38148
+		 * CALC_K256: ~100 insns each
+		 * CALC_K192: ~90 insns
+		 *    CALC_K: ~70 insns
+		 */
+		/* Calculate whitening and round subkeys */
+		for ( i = 0; i < 8; i += 2 ) {
+			CALC_K256 (w, i, q0[i], q1[i], q0[i+1], q1[i+1]);
+		}
+		for ( i = 0; i < 32; i += 2 ) {
+			CALC_K256 (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]);
+		}
 	} else if (key_len == 24) { /* 192-bit key */
 	} else if (key_len == 24) { /* 192-bit key */
 		/* Compute the S-boxes. */
 		/* Compute the S-boxes. */
 		for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
 		for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
 		        CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
 		        CALC_SB192_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
 		}
 		}
 
 
-		/* Calculate whitening and round subkeys.  The constants are
-		 * indices of subkeys, preprocessed through q0 and q1. */
-		CALC_K192 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
-		CALC_K192 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
-		CALC_K192 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
-		CALC_K192 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
-		CALC_K192 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
-		CALC_K192 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
-		CALC_K192 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
-		CALC_K192 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
-		CALC_K192 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
-		CALC_K192 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
-		CALC_K192 (k, 12, 0x18, 0x37, 0xF7, 0x71);
-		CALC_K192 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
-		CALC_K192 (k, 16, 0x43, 0x30, 0x75, 0x0F);
-		CALC_K192 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
-		CALC_K192 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
-		CALC_K192 (k, 22, 0x94, 0x06, 0x48, 0x3F);
-		CALC_K192 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
-		CALC_K192 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
-		CALC_K192 (k, 28, 0x84, 0x8A, 0x54, 0x00);
-		CALC_K192 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+		/* Calculate whitening and round subkeys */
+		for ( i = 0; i < 8; i += 2 ) {
+			CALC_K192 (w, i, q0[i], q1[i], q0[i+1], q1[i+1]);
+		}
+		for ( i = 0; i < 32; i += 2 ) {
+			CALC_K192 (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]);
+		}
 	} else { /* 128-bit key */
 	} else { /* 128-bit key */
 		/* Compute the S-boxes. */
 		/* Compute the S-boxes. */
 		for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
 		for ( i = j = 0, k = 1; i < 256; i++, j += 2, k += 2 ) {
 			CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
 			CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
 		}
 		}
 
 
-		/* Calculate whitening and round subkeys.  The constants are
-		 * indices of subkeys, preprocessed through q0 and q1. */
-		CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
-		CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
-		CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
-		CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
-		CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
-		CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
-		CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
-		CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
-		CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
-		CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
-		CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
-		CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
-		CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
-		CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
-		CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
-		CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
-		CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
-		CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
-		CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
-		CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
+		/* Calculate whitening and round subkeys */
+		for ( i = 0; i < 8; i += 2 ) {
+			CALC_K (w, i, q0[i], q1[i], q0[i+1], q1[i+1]);
+		}
+		for ( i = 0; i < 32; i += 2 ) {
+			CALC_K (k, i, q0[i+8], q1[i+8], q0[i+9], q1[i+9]);
+		}
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 4 - 6
crypto/xcbc.c

@@ -19,6 +19,7 @@
  * 	Kazunori Miyazawa <miyazawa@linux-ipv6.org>
  * 	Kazunori Miyazawa <miyazawa@linux-ipv6.org>
  */
  */
 
 
+#include <crypto/scatterwalk.h>
 #include <linux/crypto.h>
 #include <linux/crypto.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/hardirq.h>
 #include <linux/hardirq.h>
@@ -27,7 +28,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
-#include "internal.h"
 
 
 static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
 static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
 			   0x02020202, 0x02020202, 0x02020202, 0x02020202,
 			   0x02020202, 0x02020202, 0x02020202, 0x02020202,
@@ -307,7 +307,8 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
 	case 16:
 	case 16:
 		break;
 		break;
 	default:
 	default:
-		return ERR_PTR(PTR_ERR(alg));
+		inst = ERR_PTR(-EINVAL);
+		goto out_put_alg;
 	}
 	}
 
 
 	inst = crypto_alloc_instance("xcbc", alg);
 	inst = crypto_alloc_instance("xcbc", alg);
@@ -320,10 +321,7 @@ static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
 	inst->alg.cra_alignmask = alg->cra_alignmask;
 	inst->alg.cra_alignmask = alg->cra_alignmask;
 	inst->alg.cra_type = &crypto_hash_type;
 	inst->alg.cra_type = &crypto_hash_type;
 
 
-	inst->alg.cra_hash.digestsize =
-		(alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
-		CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
-				       alg->cra_blocksize;
+	inst->alg.cra_hash.digestsize = alg->cra_blocksize;
 	inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) +
 	inst->alg.cra_ctxsize = sizeof(struct crypto_xcbc_ctx) +
 				ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *));
 				ALIGN(inst->alg.cra_blocksize * 3, sizeof(void *));
 	inst->alg.cra_init = xcbc_init_tfm;
 	inst->alg.cra_init = xcbc_init_tfm;

+ 10 - 2
drivers/char/hw_random/amd-rng.c

@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
 #include <linux/hw_random.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
 
 
@@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 static struct pci_dev *amd_pdev;
 static struct pci_dev *amd_pdev;
 
 
 
 
-static int amd_rng_data_present(struct hwrng *rng)
+static int amd_rng_data_present(struct hwrng *rng, int wait)
 {
 {
 	u32 pmbase = (u32)rng->priv;
 	u32 pmbase = (u32)rng->priv;
+	int data, i;
 
 
-      	return !!(inl(pmbase + 0xF4) & 1);
+	for (i = 0; i < 20; i++) {
+		data = !!(inl(pmbase + 0xF4) & 1);
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 }
 
 
 static int amd_rng_data_read(struct hwrng *rng, u32 *data)
 static int amd_rng_data_read(struct hwrng *rng, u32 *data)

+ 6 - 18
drivers/char/hw_random/core.c

@@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng)
 		rng->cleanup(rng);
 		rng->cleanup(rng);
 }
 }
 
 
-static inline int hwrng_data_present(struct hwrng *rng)
+static inline int hwrng_data_present(struct hwrng *rng, int wait)
 {
 {
 	if (!rng->data_present)
 	if (!rng->data_present)
 		return 1;
 		return 1;
-	return rng->data_present(rng);
+	return rng->data_present(rng, wait);
 }
 }
 
 
 static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
 static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
@@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
 {
 {
 	u32 data;
 	u32 data;
 	ssize_t ret = 0;
 	ssize_t ret = 0;
-	int i, err = 0;
-	int data_present;
+	int err = 0;
 	int bytes_read;
 	int bytes_read;
 
 
 	while (size) {
 	while (size) {
@@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
 			err = -ENODEV;
 			err = -ENODEV;
 			goto out;
 			goto out;
 		}
 		}
-		if (filp->f_flags & O_NONBLOCK) {
-			data_present = hwrng_data_present(current_rng);
-		} else {
-			/* Some RNG require some time between data_reads to gather
-			 * new entropy. Poll it.
-			 */
-			for (i = 0; i < 20; i++) {
-				data_present = hwrng_data_present(current_rng);
-				if (data_present)
-					break;
-				udelay(10);
-			}
-		}
+
 		bytes_read = 0;
 		bytes_read = 0;
-		if (data_present)
+		if (hwrng_data_present(current_rng,
+				       !(filp->f_flags & O_NONBLOCK)))
 			bytes_read = hwrng_data_read(current_rng, &data);
 			bytes_read = hwrng_data_read(current_rng, &data);
 		mutex_unlock(&rng_mutex);
 		mutex_unlock(&rng_mutex);
 
 

+ 10 - 2
drivers/char/hw_random/geode-rng.c

@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
 #include <linux/hw_random.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
 
 
@@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data)
 	return 4;
 	return 4;
 }
 }
 
 
-static int geode_rng_data_present(struct hwrng *rng)
+static int geode_rng_data_present(struct hwrng *rng, int wait)
 {
 {
 	void __iomem *mem = (void __iomem *)rng->priv;
 	void __iomem *mem = (void __iomem *)rng->priv;
+	int data, i;
 
 
-	return !!(readl(mem + GEODE_RNG_STATUS_REG));
+	for (i = 0; i < 20; i++) {
+		data = !!(readl(mem + GEODE_RNG_STATUS_REG));
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 }
 
 
 
 

+ 12 - 3
drivers/char/hw_random/intel-rng.c

@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
 #include <linux/stop_machine.h>
 #include <linux/stop_machine.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
 
 
@@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem,
 	return hwstatus_get(mem);
 	return hwstatus_get(mem);
 }
 }
 
 
-static int intel_rng_data_present(struct hwrng *rng)
+static int intel_rng_data_present(struct hwrng *rng, int wait)
 {
 {
 	void __iomem *mem = (void __iomem *)rng->priv;
 	void __iomem *mem = (void __iomem *)rng->priv;
-
-	return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT);
+	int data, i;
+
+	for (i = 0; i < 20; i++) {
+		data = !!(readb(mem + INTEL_RNG_STATUS) &
+			  INTEL_RNG_DATA_PRESENT);
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 }
 
 
 static int intel_rng_data_read(struct hwrng *rng, u32 *data)
 static int intel_rng_data_read(struct hwrng *rng, u32 *data)

+ 11 - 2
drivers/char/hw_random/omap-rng.c

@@ -29,6 +29,7 @@
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 
 
 #include <asm/io.h>
 #include <asm/io.h>
 
 
@@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val)
 }
 }
 
 
 /* REVISIT: Does the status bit really work on 16xx? */
 /* REVISIT: Does the status bit really work on 16xx? */
-static int omap_rng_data_present(struct hwrng *rng)
+static int omap_rng_data_present(struct hwrng *rng, int wait)
 {
 {
-	return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+	int data, i;
+
+	for (i = 0; i < 20; i++) {
+		data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 }
 
 
 static int omap_rng_data_read(struct hwrng *rng, u32 *data)
 static int omap_rng_data_read(struct hwrng *rng, u32 *data)

+ 12 - 4
drivers/char/hw_random/pasemi-rng.c

@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/of_platform.h>
 #include <asm/of_platform.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
@@ -41,12 +42,19 @@
 
 
 #define MODULE_NAME "pasemi_rng"
 #define MODULE_NAME "pasemi_rng"
 
 
-static int pasemi_rng_data_present(struct hwrng *rng)
+static int pasemi_rng_data_present(struct hwrng *rng, int wait)
 {
 {
 	void __iomem *rng_regs = (void __iomem *)rng->priv;
 	void __iomem *rng_regs = (void __iomem *)rng->priv;
-
-	return (in_le32(rng_regs + SDCRNG_CTL_REG)
-		& SDCRNG_CTL_FVLD_M) ? 1 : 0;
+	int data, i;
+
+	for (i = 0; i < 20; i++) {
+		data = (in_le32(rng_regs + SDCRNG_CTL_REG)
+			& SDCRNG_CTL_FVLD_M) ? 1 : 0;
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 }
 
 
 static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
 static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)

+ 12 - 7
drivers/char/hw_random/via-rng.c

@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/hw_random.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
 #include <asm/cpufeature.h>
@@ -77,10 +78,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in)
 	return eax_out;
 	return eax_out;
 }
 }
 
 
-static int via_rng_data_present(struct hwrng *rng)
+static int via_rng_data_present(struct hwrng *rng, int wait)
 {
 {
 	u32 bytes_out;
 	u32 bytes_out;
 	u32 *via_rng_datum = (u32 *)(&rng->priv);
 	u32 *via_rng_datum = (u32 *)(&rng->priv);
+	int i;
 
 
 	/* We choose the recommended 1-byte-per-instruction RNG rate,
 	/* We choose the recommended 1-byte-per-instruction RNG rate,
 	 * for greater randomness at the expense of speed.  Larger
 	 * for greater randomness at the expense of speed.  Larger
@@ -95,12 +97,15 @@ static int via_rng_data_present(struct hwrng *rng)
 	 * completes.
 	 * completes.
 	 */
 	 */
 
 
-	*via_rng_datum = 0; /* paranoia, not really necessary */
-	bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
-	bytes_out &= VIA_XSTORE_CNT_MASK;
-	if (bytes_out == 0)
-		return 0;
-	return 1;
+	for (i = 0; i < 20; i++) {
+		*via_rng_datum = 0; /* paranoia, not really necessary */
+		bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
+		bytes_out &= VIA_XSTORE_CNT_MASK;
+		if (bytes_out || !wait)
+			break;
+		udelay(10);
+	}
+	return bytes_out ? 1 : 0;
 }
 }
 
 
 static int via_rng_data_read(struct hwrng *rng, u32 *data)
 static int via_rng_data_read(struct hwrng *rng, u32 *data)

+ 11 - 0
drivers/crypto/Kconfig

@@ -83,4 +83,15 @@ config ZCRYPT_MONOLITHIC
 	  that contains all parts of the crypto device driver (ap bus,
 	  that contains all parts of the crypto device driver (ap bus,
 	  request router and all the card drivers).
 	  request router and all the card drivers).
 
 
+config CRYPTO_DEV_HIFN_795X
+	tristate "Driver HIFN 795x crypto accelerator chips"
+	select CRYPTO_DES
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	depends on PCI
+	help
+	  This option allows you to have support for HIFN 795x crypto adapters.
+
+
+
 endif # CRYPTO_HW
 endif # CRYPTO_HW

+ 1 - 0
drivers/crypto/Makefile

@@ -1,3 +1,4 @@
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o

+ 211 - 87
drivers/crypto/geode-aes.c

@@ -13,44 +13,13 @@
 #include <linux/crypto.h>
 #include <linux/crypto.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <crypto/algapi.h>
 #include <crypto/algapi.h>
+#include <crypto/aes.h>
 
 
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/delay.h>
 #include <asm/delay.h>
 
 
 #include "geode-aes.h"
 #include "geode-aes.h"
 
 
-/* Register definitions */
-
-#define AES_CTRLA_REG  0x0000
-
-#define AES_CTRL_START     0x01
-#define AES_CTRL_DECRYPT   0x00
-#define AES_CTRL_ENCRYPT   0x02
-#define AES_CTRL_WRKEY     0x04
-#define AES_CTRL_DCA       0x08
-#define AES_CTRL_SCA       0x10
-#define AES_CTRL_CBC       0x20
-
-#define AES_INTR_REG  0x0008
-
-#define AES_INTRA_PENDING (1 << 16)
-#define AES_INTRB_PENDING (1 << 17)
-
-#define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
-#define AES_INTR_MASK     0x07
-
-#define AES_SOURCEA_REG   0x0010
-#define AES_DSTA_REG      0x0014
-#define AES_LENA_REG      0x0018
-#define AES_WRITEKEY0_REG 0x0030
-#define AES_WRITEIV0_REG  0x0040
-
-/*  A very large counter that is used to gracefully bail out of an
- *  operation in case of trouble
- */
-
-#define AES_OP_TIMEOUT    0x50000
-
 /* Static structures */
 /* Static structures */
 
 
 static void __iomem * _iobase;
 static void __iomem * _iobase;
@@ -87,9 +56,10 @@ do_crypt(void *src, void *dst, int len, u32 flags)
 	/* Start the operation */
 	/* Start the operation */
 	iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG);
 	iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG);
 
 
-	do
+	do {
 		status = ioread32(_iobase + AES_INTR_REG);
 		status = ioread32(_iobase + AES_INTR_REG);
-	while(!(status & AES_INTRA_PENDING) && --counter);
+		cpu_relax();
+	} while(!(status & AES_INTRA_PENDING) && --counter);
 
 
 	/* Clear the event */
 	/* Clear the event */
 	iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG);
 	iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG);
@@ -101,6 +71,7 @@ geode_aes_crypt(struct geode_aes_op *op)
 {
 {
 	u32 flags = 0;
 	u32 flags = 0;
 	unsigned long iflags;
 	unsigned long iflags;
+	int ret;
 
 
 	if (op->len == 0)
 	if (op->len == 0)
 		return 0;
 		return 0;
@@ -129,7 +100,8 @@ geode_aes_crypt(struct geode_aes_op *op)
 		_writefield(AES_WRITEKEY0_REG, op->key);
 		_writefield(AES_WRITEKEY0_REG, op->key);
 	}
 	}
 
 
-	do_crypt(op->src, op->dst, op->len, flags);
+	ret = do_crypt(op->src, op->dst, op->len, flags);
+	BUG_ON(ret);
 
 
 	if (op->mode == AES_MODE_CBC)
 	if (op->mode == AES_MODE_CBC)
 		_readfield(AES_WRITEIV0_REG, op->iv);
 		_readfield(AES_WRITEIV0_REG, op->iv);
@@ -141,18 +113,103 @@ geode_aes_crypt(struct geode_aes_op *op)
 
 
 /* CRYPTO-API Functions */
 /* CRYPTO-API Functions */
 
 
-static int
-geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len)
+static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
+		unsigned int len)
 {
 {
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	unsigned int ret;
 
 
-	if (len != AES_KEY_LENGTH) {
+	op->keylen = len;
+
+	if (len == AES_KEYSIZE_128) {
+		memcpy(op->key, key, len);
+		return 0;
+	}
+
+	if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+		/* not supported at all */
 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	memcpy(op->key, key, len);
-	return 0;
+	/*
+	 * The requested key size is not supported by HW, do a fallback
+	 */
+	op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+
+	ret = crypto_cipher_setkey(op->fallback.cip, key, len);
+	if (ret) {
+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+		tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+	}
+	return ret;
+}
+
+static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
+		unsigned int len)
+{
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	unsigned int ret;
+
+	op->keylen = len;
+
+	if (len == AES_KEYSIZE_128) {
+		memcpy(op->key, key, len);
+		return 0;
+	}
+
+	if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+		/* not supported at all */
+		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	/*
+	 * The requested key size is not supported by HW, do a fallback
+	 */
+	op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+
+	ret = crypto_blkcipher_setkey(op->fallback.blk, key, len);
+	if (ret) {
+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+		tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+	}
+	return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	unsigned int ret;
+	struct crypto_blkcipher *tfm;
+	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+	tfm = desc->tfm;
+	desc->tfm = op->fallback.blk;
+
+	ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+	desc->tfm = tfm;
+	return ret;
+}
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	unsigned int ret;
+	struct crypto_blkcipher *tfm;
+	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+	tfm = desc->tfm;
+	desc->tfm = op->fallback.blk;
+
+	ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+	desc->tfm = tfm;
+	return ret;
 }
 }
 
 
 static void
 static void
@@ -160,8 +217,10 @@ geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
 
-	if ((out == NULL) || (in == NULL))
+	if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+		crypto_cipher_encrypt_one(op->fallback.cip, out, in);
 		return;
 		return;
+	}
 
 
 	op->src = (void *) in;
 	op->src = (void *) in;
 	op->dst = (void *) out;
 	op->dst = (void *) out;
@@ -179,8 +238,10 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
 
-	if ((out == NULL) || (in == NULL))
+	if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+		crypto_cipher_decrypt_one(op->fallback.cip, out, in);
 		return;
 		return;
+	}
 
 
 	op->src = (void *) in;
 	op->src = (void *) in;
 	op->dst = (void *) out;
 	op->dst = (void *) out;
@@ -192,24 +253,50 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 	geode_aes_crypt(op);
 	geode_aes_crypt(op);
 }
 }
 
 
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+	const char *name = tfm->__crt_alg->cra_name;
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	op->fallback.cip = crypto_alloc_cipher(name, 0,
+				CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+	if (IS_ERR(op->fallback.cip)) {
+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		return PTR_ERR(op->fallback.blk);
+	}
+
+	return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	crypto_free_cipher(op->fallback.cip);
+	op->fallback.cip = NULL;
+}
 
 
 static struct crypto_alg geode_alg = {
 static struct crypto_alg geode_alg = {
-	.cra_name               =       "aes",
-	.cra_driver_name	=       "geode-aes-128",
-	.cra_priority           =       300,
-	.cra_alignmask          =       15,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_name			=	"aes",
+	.cra_driver_name	=	"geode-aes",
+	.cra_priority		=	300,
+	.cra_alignmask		=	15,
+	.cra_flags			=	CRYPTO_ALG_TYPE_CIPHER |
+							CRYPTO_ALG_NEED_FALLBACK,
+	.cra_init			=	fallback_init_cip,
+	.cra_exit			=	fallback_exit_cip,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(geode_alg.cra_list),
-	.cra_u			=	{
-		.cipher = {
-			.cia_min_keysize	=  AES_KEY_LENGTH,
-			.cia_max_keysize	=  AES_KEY_LENGTH,
-			.cia_setkey		=  geode_setkey,
-			.cia_encrypt		=  geode_encrypt,
-			.cia_decrypt		=  geode_decrypt
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(geode_alg.cra_list),
+	.cra_u				=	{
+		.cipher	=	{
+			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
+			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
+			.cia_setkey			=	geode_setkey_cip,
+			.cia_encrypt		=	geode_encrypt,
+			.cia_decrypt		=	geode_decrypt
 		}
 		}
 	}
 	}
 };
 };
@@ -223,8 +310,12 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err, ret;
 	int err, ret;
 
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_dec(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
+	op->iv = walk.iv;
 
 
 	while((nbytes = walk.nbytes)) {
 	while((nbytes = walk.nbytes)) {
 		op->src = walk.src.virt.addr,
 		op->src = walk.src.virt.addr,
@@ -233,13 +324,9 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
 		op->dir = AES_DIR_DECRYPT;
 		op->dir = AES_DIR_DECRYPT;
 
 
-		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
-
 		ret = geode_aes_crypt(op);
 		ret = geode_aes_crypt(op);
 
 
-		memcpy(walk.iv, op->iv, AES_IV_LENGTH);
 		nbytes -= ret;
 		nbytes -= ret;
-
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 	}
 
 
@@ -255,8 +342,12 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err, ret;
 	int err, ret;
 
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_enc(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
+	op->iv = walk.iv;
 
 
 	while((nbytes = walk.nbytes)) {
 	while((nbytes = walk.nbytes)) {
 		op->src = walk.src.virt.addr,
 		op->src = walk.src.virt.addr,
@@ -265,8 +356,6 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
 		op->dir = AES_DIR_ENCRYPT;
 		op->dir = AES_DIR_ENCRYPT;
 
 
-		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
-
 		ret = geode_aes_crypt(op);
 		ret = geode_aes_crypt(op);
 		nbytes -= ret;
 		nbytes -= ret;
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 		err = blkcipher_walk_done(desc, &walk, nbytes);
@@ -275,22 +364,49 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
 	return err;
 	return err;
 }
 }
 
 
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+	const char *name = tfm->__crt_alg->cra_name;
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	op->fallback.blk = crypto_alloc_blkcipher(name, 0,
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+	if (IS_ERR(op->fallback.blk)) {
+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		return PTR_ERR(op->fallback.blk);
+	}
+
+	return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	crypto_free_blkcipher(op->fallback.blk);
+	op->fallback.blk = NULL;
+}
+
 static struct crypto_alg geode_cbc_alg = {
 static struct crypto_alg geode_cbc_alg = {
 	.cra_name		=	"cbc(aes)",
 	.cra_name		=	"cbc(aes)",
-	.cra_driver_name	=	"cbc-aes-geode-128",
+	.cra_driver_name	=	"cbc-aes-geode",
 	.cra_priority		=	400,
 	.cra_priority		=	400,
-	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_flags			=	CRYPTO_ALG_TYPE_BLKCIPHER |
+							CRYPTO_ALG_NEED_FALLBACK,
+	.cra_init			=	fallback_init_blk,
+	.cra_exit			=	fallback_exit_blk,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_alignmask		=	15,
 	.cra_alignmask		=	15,
-	.cra_type		=	&crypto_blkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
-	.cra_u			=	{
-		.blkcipher = {
-			.min_keysize		=	AES_KEY_LENGTH,
-			.max_keysize		=	AES_KEY_LENGTH,
-			.setkey			=	geode_setkey,
+	.cra_type			=	&crypto_blkcipher_type,
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
+	.cra_u				=	{
+		.blkcipher	=	{
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey			=	geode_setkey_blk,
 			.encrypt		=	geode_cbc_encrypt,
 			.encrypt		=	geode_cbc_encrypt,
 			.decrypt		=	geode_cbc_decrypt,
 			.decrypt		=	geode_cbc_decrypt,
 			.ivsize			=	AES_IV_LENGTH,
 			.ivsize			=	AES_IV_LENGTH,
@@ -307,6 +423,9 @@ geode_ecb_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err, ret;
 	int err, ret;
 
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_dec(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
 
 
@@ -334,6 +453,9 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err, ret;
 	int err, ret;
 
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_enc(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
 
 
@@ -353,28 +475,31 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
 }
 }
 
 
 static struct crypto_alg geode_ecb_alg = {
 static struct crypto_alg geode_ecb_alg = {
-	.cra_name		=	"ecb(aes)",
-	.cra_driver_name	=	"ecb-aes-geode-128",
+	.cra_name			=	"ecb(aes)",
+	.cra_driver_name	=	"ecb-aes-geode",
 	.cra_priority		=	400,
 	.cra_priority		=	400,
-	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_flags			=	CRYPTO_ALG_TYPE_BLKCIPHER |
+							CRYPTO_ALG_NEED_FALLBACK,
+	.cra_init			=	fallback_init_blk,
+	.cra_exit			=	fallback_exit_blk,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_alignmask		=	15,
 	.cra_alignmask		=	15,
-	.cra_type		=	&crypto_blkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
-	.cra_u			=	{
-		.blkcipher = {
-			.min_keysize		=	AES_KEY_LENGTH,
-			.max_keysize		=	AES_KEY_LENGTH,
-			.setkey			=	geode_setkey,
+	.cra_type			=	&crypto_blkcipher_type,
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
+	.cra_u				=	{
+		.blkcipher	=	{
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey			=	geode_setkey_blk,
 			.encrypt		=	geode_ecb_encrypt,
 			.encrypt		=	geode_ecb_encrypt,
 			.decrypt		=	geode_ecb_decrypt,
 			.decrypt		=	geode_ecb_decrypt,
 		}
 		}
 	}
 	}
 };
 };
 
 
-static void
+static void __devexit
 geode_aes_remove(struct pci_dev *dev)
 geode_aes_remove(struct pci_dev *dev)
 {
 {
 	crypto_unregister_alg(&geode_alg);
 	crypto_unregister_alg(&geode_alg);
@@ -389,7 +514,7 @@ geode_aes_remove(struct pci_dev *dev)
 }
 }
 
 
 
 
-static int
+static int __devinit
 geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 {
 	int ret;
 	int ret;
@@ -397,7 +522,7 @@ geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	if ((ret = pci_enable_device(dev)))
 	if ((ret = pci_enable_device(dev)))
 		return ret;
 		return ret;
 
 
-	if ((ret = pci_request_regions(dev, "geode-aes-128")))
+	if ((ret = pci_request_regions(dev, "geode-aes")))
 		goto eenable;
 		goto eenable;
 
 
 	_iobase = pci_iomap(dev, 0, 0);
 	_iobase = pci_iomap(dev, 0, 0);
@@ -472,7 +597,6 @@ geode_aes_exit(void)
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("aes");
 
 
 module_init(geode_aes_init);
 module_init(geode_aes_init);
 module_exit(geode_aes_exit);
 module_exit(geode_aes_exit);

+ 41 - 3
drivers/crypto/geode-aes.h

@@ -9,9 +9,9 @@
 #ifndef _GEODE_AES_H_
 #ifndef _GEODE_AES_H_
 #define _GEODE_AES_H_
 #define _GEODE_AES_H_
 
 
-#define AES_KEY_LENGTH 16
+/* driver logic flags */
 #define AES_IV_LENGTH  16
 #define AES_IV_LENGTH  16
-
+#define AES_KEY_LENGTH 16
 #define AES_MIN_BLOCK_SIZE 16
 #define AES_MIN_BLOCK_SIZE 16
 
 
 #define AES_MODE_ECB 0
 #define AES_MODE_ECB 0
@@ -22,6 +22,38 @@
 
 
 #define AES_FLAGS_HIDDENKEY (1 << 0)
 #define AES_FLAGS_HIDDENKEY (1 << 0)
 
 
+/* Register definitions */
+
+#define AES_CTRLA_REG  0x0000
+
+#define AES_CTRL_START     0x01
+#define AES_CTRL_DECRYPT   0x00
+#define AES_CTRL_ENCRYPT   0x02
+#define AES_CTRL_WRKEY     0x04
+#define AES_CTRL_DCA       0x08
+#define AES_CTRL_SCA       0x10
+#define AES_CTRL_CBC       0x20
+
+#define AES_INTR_REG  0x0008
+
+#define AES_INTRA_PENDING (1 << 16)
+#define AES_INTRB_PENDING (1 << 17)
+
+#define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
+#define AES_INTR_MASK     0x07
+
+#define AES_SOURCEA_REG   0x0010
+#define AES_DSTA_REG      0x0014
+#define AES_LENA_REG      0x0018
+#define AES_WRITEKEY0_REG 0x0030
+#define AES_WRITEIV0_REG  0x0040
+
+/*  A very large counter that is used to gracefully bail out of an
+ *  operation in case of trouble
+ */
+
+#define AES_OP_TIMEOUT    0x50000
+
 struct geode_aes_op {
 struct geode_aes_op {
 
 
 	void *src;
 	void *src;
@@ -33,7 +65,13 @@ struct geode_aes_op {
 	int len;
 	int len;
 
 
 	u8 key[AES_KEY_LENGTH];
 	u8 key[AES_KEY_LENGTH];
-	u8 iv[AES_IV_LENGTH];
+	u8 *iv;
+
+	union {
+		struct crypto_blkcipher *blk;
+		struct crypto_cipher *cip;
+	} fallback;
+	u32 keylen;
 };
 };
 
 
 #endif
 #endif

+ 2838 - 0
drivers/crypto/hifn_795x.c

@@ -0,0 +1,2838 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mod_devicetable.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <linux/ktime.h>
+
+#include <crypto/algapi.h>
+#include <crypto/des.h>
+
+#include <asm/kmap_types.h>
+
+#undef dprintk
+
+#define HIFN_TEST
+//#define HIFN_DEBUG
+
+#ifdef HIFN_DEBUG
+#define dprintk(f, a...) 	printk(f, ##a)
+#else
+#define dprintk(f, a...)	do {} while (0)
+#endif
+
+static char hifn_pll_ref[sizeof("extNNN")] = "ext";
+module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444);
+MODULE_PARM_DESC(hifn_pll_ref,
+		 "PLL reference clock (pci[freq] or ext[freq], default ext)");
+
+static atomic_t hifn_dev_number;
+
+#define ACRYPTO_OP_DECRYPT	0
+#define ACRYPTO_OP_ENCRYPT	1
+#define ACRYPTO_OP_HMAC		2
+#define ACRYPTO_OP_RNG		3
+
+#define ACRYPTO_MODE_ECB		0
+#define ACRYPTO_MODE_CBC		1
+#define ACRYPTO_MODE_CFB		2
+#define ACRYPTO_MODE_OFB		3
+
+#define ACRYPTO_TYPE_AES_128	0
+#define ACRYPTO_TYPE_AES_192	1
+#define ACRYPTO_TYPE_AES_256	2
+#define ACRYPTO_TYPE_3DES	3
+#define ACRYPTO_TYPE_DES	4
+
+#define PCI_VENDOR_ID_HIFN		0x13A3
+#define PCI_DEVICE_ID_HIFN_7955		0x0020
+#define	PCI_DEVICE_ID_HIFN_7956		0x001d
+
+/* I/O region sizes */
+
+#define HIFN_BAR0_SIZE			0x1000
+#define HIFN_BAR1_SIZE			0x2000
+#define HIFN_BAR2_SIZE			0x8000
+
+/* DMA registres */
+
+#define HIFN_DMA_CRA 			0x0C	/* DMA Command Ring Address */
+#define HIFN_DMA_SDRA 			0x1C	/* DMA Source Data Ring Address */
+#define HIFN_DMA_RRA			0x2C	/* DMA Result Ring Address */
+#define HIFN_DMA_DDRA			0x3C	/* DMA Destination Data Ring Address */
+#define HIFN_DMA_STCTL			0x40	/* DMA Status and Control */
+#define HIFN_DMA_INTREN 		0x44	/* DMA Interrupt Enable */
+#define HIFN_DMA_CFG1			0x48	/* DMA Configuration #1 */
+#define HIFN_DMA_CFG2			0x6C	/* DMA Configuration #2 */
+#define HIFN_CHIP_ID			0x98	/* Chip ID */
+
+/*
+ * Processing Unit Registers (offset from BASEREG0)
+ */
+#define	HIFN_0_PUDATA		0x00	/* Processing Unit Data */
+#define	HIFN_0_PUCTRL		0x04	/* Processing Unit Control */
+#define	HIFN_0_PUISR		0x08	/* Processing Unit Interrupt Status */
+#define	HIFN_0_PUCNFG		0x0c	/* Processing Unit Configuration */
+#define	HIFN_0_PUIER		0x10	/* Processing Unit Interrupt Enable */
+#define	HIFN_0_PUSTAT		0x14	/* Processing Unit Status/Chip ID */
+#define	HIFN_0_FIFOSTAT		0x18	/* FIFO Status */
+#define	HIFN_0_FIFOCNFG		0x1c	/* FIFO Configuration */
+#define	HIFN_0_SPACESIZE	0x20	/* Register space size */
+
+/* Processing Unit Control Register (HIFN_0_PUCTRL) */
+#define	HIFN_PUCTRL_CLRSRCFIFO	0x0010	/* clear source fifo */
+#define	HIFN_PUCTRL_STOP	0x0008	/* stop pu */
+#define	HIFN_PUCTRL_LOCKRAM	0x0004	/* lock ram */
+#define	HIFN_PUCTRL_DMAENA	0x0002	/* enable dma */
+#define	HIFN_PUCTRL_RESET	0x0001	/* Reset processing unit */
+
+/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */
+#define	HIFN_PUISR_CMDINVAL	0x8000	/* Invalid command interrupt */
+#define	HIFN_PUISR_DATAERR	0x4000	/* Data error interrupt */
+#define	HIFN_PUISR_SRCFIFO	0x2000	/* Source FIFO ready interrupt */
+#define	HIFN_PUISR_DSTFIFO	0x1000	/* Destination FIFO ready interrupt */
+#define	HIFN_PUISR_DSTOVER	0x0200	/* Destination overrun interrupt */
+#define	HIFN_PUISR_SRCCMD	0x0080	/* Source command interrupt */
+#define	HIFN_PUISR_SRCCTX	0x0040	/* Source context interrupt */
+#define	HIFN_PUISR_SRCDATA	0x0020	/* Source data interrupt */
+#define	HIFN_PUISR_DSTDATA	0x0010	/* Destination data interrupt */
+#define	HIFN_PUISR_DSTRESULT	0x0004	/* Destination result interrupt */
+
+/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */
+#define	HIFN_PUCNFG_DRAMMASK	0xe000	/* DRAM size mask */
+#define	HIFN_PUCNFG_DSZ_256K	0x0000	/* 256k dram */
+#define	HIFN_PUCNFG_DSZ_512K	0x2000	/* 512k dram */
+#define	HIFN_PUCNFG_DSZ_1M	0x4000	/* 1m dram */
+#define	HIFN_PUCNFG_DSZ_2M	0x6000	/* 2m dram */
+#define	HIFN_PUCNFG_DSZ_4M	0x8000	/* 4m dram */
+#define	HIFN_PUCNFG_DSZ_8M	0xa000	/* 8m dram */
+#define	HIFN_PUNCFG_DSZ_16M	0xc000	/* 16m dram */
+#define	HIFN_PUCNFG_DSZ_32M	0xe000	/* 32m dram */
+#define	HIFN_PUCNFG_DRAMREFRESH	0x1800	/* DRAM refresh rate mask */
+#define	HIFN_PUCNFG_DRFR_512	0x0000	/* 512 divisor of ECLK */
+#define	HIFN_PUCNFG_DRFR_256	0x0800	/* 256 divisor of ECLK */
+#define	HIFN_PUCNFG_DRFR_128	0x1000	/* 128 divisor of ECLK */
+#define	HIFN_PUCNFG_TCALLPHASES	0x0200	/* your guess is as good as mine... */
+#define	HIFN_PUCNFG_TCDRVTOTEM	0x0100	/* your guess is as good as mine... */
+#define	HIFN_PUCNFG_BIGENDIAN	0x0080	/* DMA big endian mode */
+#define	HIFN_PUCNFG_BUS32	0x0040	/* Bus width 32bits */
+#define	HIFN_PUCNFG_BUS16	0x0000	/* Bus width 16 bits */
+#define	HIFN_PUCNFG_CHIPID	0x0020	/* Allow chipid from PUSTAT */
+#define	HIFN_PUCNFG_DRAM	0x0010	/* Context RAM is DRAM */
+#define	HIFN_PUCNFG_SRAM	0x0000	/* Context RAM is SRAM */
+#define	HIFN_PUCNFG_COMPSING	0x0004	/* Enable single compression context */
+#define	HIFN_PUCNFG_ENCCNFG	0x0002	/* Encryption configuration */
+
+/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */
+#define	HIFN_PUIER_CMDINVAL	0x8000	/* Invalid command interrupt */
+#define	HIFN_PUIER_DATAERR	0x4000	/* Data error interrupt */
+#define	HIFN_PUIER_SRCFIFO	0x2000	/* Source FIFO ready interrupt */
+#define	HIFN_PUIER_DSTFIFO	0x1000	/* Destination FIFO ready interrupt */
+#define	HIFN_PUIER_DSTOVER	0x0200	/* Destination overrun interrupt */
+#define	HIFN_PUIER_SRCCMD	0x0080	/* Source command interrupt */
+#define	HIFN_PUIER_SRCCTX	0x0040	/* Source context interrupt */
+#define	HIFN_PUIER_SRCDATA	0x0020	/* Source data interrupt */
+#define	HIFN_PUIER_DSTDATA	0x0010	/* Destination data interrupt */
+#define	HIFN_PUIER_DSTRESULT	0x0004	/* Destination result interrupt */
+
+/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */
+#define	HIFN_PUSTAT_CMDINVAL	0x8000	/* Invalid command interrupt */
+#define	HIFN_PUSTAT_DATAERR	0x4000	/* Data error interrupt */
+#define	HIFN_PUSTAT_SRCFIFO	0x2000	/* Source FIFO ready interrupt */
+#define	HIFN_PUSTAT_DSTFIFO	0x1000	/* Destination FIFO ready interrupt */
+#define	HIFN_PUSTAT_DSTOVER	0x0200	/* Destination overrun interrupt */
+#define	HIFN_PUSTAT_SRCCMD	0x0080	/* Source command interrupt */
+#define	HIFN_PUSTAT_SRCCTX	0x0040	/* Source context interrupt */
+#define	HIFN_PUSTAT_SRCDATA	0x0020	/* Source data interrupt */
+#define	HIFN_PUSTAT_DSTDATA	0x0010	/* Destination data interrupt */
+#define	HIFN_PUSTAT_DSTRESULT	0x0004	/* Destination result interrupt */
+#define	HIFN_PUSTAT_CHIPREV	0x00ff	/* Chip revision mask */
+#define	HIFN_PUSTAT_CHIPENA	0xff00	/* Chip enabled mask */
+#define	HIFN_PUSTAT_ENA_2	0x1100	/* Level 2 enabled */
+#define	HIFN_PUSTAT_ENA_1	0x1000	/* Level 1 enabled */
+#define	HIFN_PUSTAT_ENA_0	0x3000	/* Level 0 enabled */
+#define	HIFN_PUSTAT_REV_2	0x0020	/* 7751 PT6/2 */
+#define	HIFN_PUSTAT_REV_3	0x0030	/* 7751 PT6/3 */
+
+/* FIFO Status Register (HIFN_0_FIFOSTAT) */
+#define	HIFN_FIFOSTAT_SRC	0x7f00	/* Source FIFO available */
+#define	HIFN_FIFOSTAT_DST	0x007f	/* Destination FIFO available */
+
+/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */
+#define	HIFN_FIFOCNFG_THRESHOLD	0x0400	/* must be written as 1 */
+
+/*
+ * DMA Interface Registers (offset from BASEREG1)
+ */
+#define	HIFN_1_DMA_CRAR		0x0c	/* DMA Command Ring Address */
+#define	HIFN_1_DMA_SRAR		0x1c	/* DMA Source Ring Address */
+#define	HIFN_1_DMA_RRAR		0x2c	/* DMA Result Ring Address */
+#define	HIFN_1_DMA_DRAR		0x3c	/* DMA Destination Ring Address */
+#define	HIFN_1_DMA_CSR		0x40	/* DMA Status and Control */
+#define	HIFN_1_DMA_IER		0x44	/* DMA Interrupt Enable */
+#define	HIFN_1_DMA_CNFG		0x48	/* DMA Configuration */
+#define	HIFN_1_PLL		0x4c	/* 795x: PLL config */
+#define	HIFN_1_7811_RNGENA	0x60	/* 7811: rng enable */
+#define	HIFN_1_7811_RNGCFG	0x64	/* 7811: rng config */
+#define	HIFN_1_7811_RNGDAT	0x68	/* 7811: rng data */
+#define	HIFN_1_7811_RNGSTS	0x6c	/* 7811: rng status */
+#define	HIFN_1_7811_MIPSRST	0x94	/* 7811: MIPS reset */
+#define	HIFN_1_REVID		0x98	/* Revision ID */
+#define	HIFN_1_UNLOCK_SECRET1	0xf4
+#define	HIFN_1_UNLOCK_SECRET2	0xfc
+#define	HIFN_1_PUB_RESET	0x204	/* Public/RNG Reset */
+#define	HIFN_1_PUB_BASE		0x300	/* Public Base Address */
+#define	HIFN_1_PUB_OPLEN	0x304	/* Public Operand Length */
+#define	HIFN_1_PUB_OP		0x308	/* Public Operand */
+#define	HIFN_1_PUB_STATUS	0x30c	/* Public Status */
+#define	HIFN_1_PUB_IEN		0x310	/* Public Interrupt enable */
+#define	HIFN_1_RNG_CONFIG	0x314	/* RNG config */
+#define	HIFN_1_RNG_DATA		0x318	/* RNG data */
+#define	HIFN_1_PUB_MEM		0x400	/* start of Public key memory */
+#define	HIFN_1_PUB_MEMEND	0xbff	/* end of Public key memory */
+
+/* DMA Status and Control Register (HIFN_1_DMA_CSR) */
+#define	HIFN_DMACSR_D_CTRLMASK	0xc0000000	/* Destinition Ring Control */
+#define	HIFN_DMACSR_D_CTRL_NOP	0x00000000	/* Dest. Control: no-op */
+#define	HIFN_DMACSR_D_CTRL_DIS	0x40000000	/* Dest. Control: disable */
+#define	HIFN_DMACSR_D_CTRL_ENA	0x80000000	/* Dest. Control: enable */
+#define	HIFN_DMACSR_D_ABORT	0x20000000	/* Destinition Ring PCIAbort */
+#define	HIFN_DMACSR_D_DONE	0x10000000	/* Destinition Ring Done */
+#define	HIFN_DMACSR_D_LAST	0x08000000	/* Destinition Ring Last */
+#define	HIFN_DMACSR_D_WAIT	0x04000000	/* Destinition Ring Waiting */
+#define	HIFN_DMACSR_D_OVER	0x02000000	/* Destinition Ring Overflow */
+#define	HIFN_DMACSR_R_CTRL	0x00c00000	/* Result Ring Control */
+#define	HIFN_DMACSR_R_CTRL_NOP	0x00000000	/* Result Control: no-op */
+#define	HIFN_DMACSR_R_CTRL_DIS	0x00400000	/* Result Control: disable */
+#define	HIFN_DMACSR_R_CTRL_ENA	0x00800000	/* Result Control: enable */
+#define	HIFN_DMACSR_R_ABORT	0x00200000	/* Result Ring PCI Abort */
+#define	HIFN_DMACSR_R_DONE	0x00100000	/* Result Ring Done */
+#define	HIFN_DMACSR_R_LAST	0x00080000	/* Result Ring Last */
+#define	HIFN_DMACSR_R_WAIT	0x00040000	/* Result Ring Waiting */
+#define	HIFN_DMACSR_R_OVER	0x00020000	/* Result Ring Overflow */
+#define	HIFN_DMACSR_S_CTRL	0x0000c000	/* Source Ring Control */
+#define	HIFN_DMACSR_S_CTRL_NOP	0x00000000	/* Source Control: no-op */
+#define	HIFN_DMACSR_S_CTRL_DIS	0x00004000	/* Source Control: disable */
+#define	HIFN_DMACSR_S_CTRL_ENA	0x00008000	/* Source Control: enable */
+#define	HIFN_DMACSR_S_ABORT	0x00002000	/* Source Ring PCI Abort */
+#define	HIFN_DMACSR_S_DONE	0x00001000	/* Source Ring Done */
+#define	HIFN_DMACSR_S_LAST	0x00000800	/* Source Ring Last */
+#define	HIFN_DMACSR_S_WAIT	0x00000400	/* Source Ring Waiting */
+#define	HIFN_DMACSR_ILLW	0x00000200	/* Illegal write (7811 only) */
+#define	HIFN_DMACSR_ILLR	0x00000100	/* Illegal read (7811 only) */
+#define	HIFN_DMACSR_C_CTRL	0x000000c0	/* Command Ring Control */
+#define	HIFN_DMACSR_C_CTRL_NOP	0x00000000	/* Command Control: no-op */
+#define	HIFN_DMACSR_C_CTRL_DIS	0x00000040	/* Command Control: disable */
+#define	HIFN_DMACSR_C_CTRL_ENA	0x00000080	/* Command Control: enable */
+#define	HIFN_DMACSR_C_ABORT	0x00000020	/* Command Ring PCI Abort */
+#define	HIFN_DMACSR_C_DONE	0x00000010	/* Command Ring Done */
+#define	HIFN_DMACSR_C_LAST	0x00000008	/* Command Ring Last */
+#define	HIFN_DMACSR_C_WAIT	0x00000004	/* Command Ring Waiting */
+#define	HIFN_DMACSR_PUBDONE	0x00000002	/* Public op done (7951 only) */
+#define	HIFN_DMACSR_ENGINE	0x00000001	/* Command Ring Engine IRQ */
+
+/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */
+#define	HIFN_DMAIER_D_ABORT	0x20000000	/* Destination Ring PCIAbort */
+#define	HIFN_DMAIER_D_DONE	0x10000000	/* Destination Ring Done */
+#define	HIFN_DMAIER_D_LAST	0x08000000	/* Destination Ring Last */
+#define	HIFN_DMAIER_D_WAIT	0x04000000	/* Destination Ring Waiting */
+#define	HIFN_DMAIER_D_OVER	0x02000000	/* Destination Ring Overflow */
+#define	HIFN_DMAIER_R_ABORT	0x00200000	/* Result Ring PCI Abort */
+#define	HIFN_DMAIER_R_DONE	0x00100000	/* Result Ring Done */
+#define	HIFN_DMAIER_R_LAST	0x00080000	/* Result Ring Last */
+#define	HIFN_DMAIER_R_WAIT	0x00040000	/* Result Ring Waiting */
+#define	HIFN_DMAIER_R_OVER	0x00020000	/* Result Ring Overflow */
+#define	HIFN_DMAIER_S_ABORT	0x00002000	/* Source Ring PCI Abort */
+#define	HIFN_DMAIER_S_DONE	0x00001000	/* Source Ring Done */
+#define	HIFN_DMAIER_S_LAST	0x00000800	/* Source Ring Last */
+#define	HIFN_DMAIER_S_WAIT	0x00000400	/* Source Ring Waiting */
+#define	HIFN_DMAIER_ILLW	0x00000200	/* Illegal write (7811 only) */
+#define	HIFN_DMAIER_ILLR	0x00000100	/* Illegal read (7811 only) */
+#define	HIFN_DMAIER_C_ABORT	0x00000020	/* Command Ring PCI Abort */
+#define	HIFN_DMAIER_C_DONE	0x00000010	/* Command Ring Done */
+#define	HIFN_DMAIER_C_LAST	0x00000008	/* Command Ring Last */
+#define	HIFN_DMAIER_C_WAIT	0x00000004	/* Command Ring Waiting */
+#define	HIFN_DMAIER_PUBDONE	0x00000002	/* public op done (7951 only) */
+#define	HIFN_DMAIER_ENGINE	0x00000001	/* Engine IRQ */
+
+/* DMA Configuration Register (HIFN_1_DMA_CNFG) */
+#define	HIFN_DMACNFG_BIGENDIAN	0x10000000	/* big endian mode */
+#define	HIFN_DMACNFG_POLLFREQ	0x00ff0000	/* Poll frequency mask */
+#define	HIFN_DMACNFG_UNLOCK	0x00000800
+#define	HIFN_DMACNFG_POLLINVAL	0x00000700	/* Invalid Poll Scalar */
+#define	HIFN_DMACNFG_LAST	0x00000010	/* Host control LAST bit */
+#define	HIFN_DMACNFG_MODE	0x00000004	/* DMA mode */
+#define	HIFN_DMACNFG_DMARESET	0x00000002	/* DMA Reset # */
+#define	HIFN_DMACNFG_MSTRESET	0x00000001	/* Master Reset # */
+
+/* PLL configuration register */
+#define HIFN_PLL_REF_CLK_HBI	0x00000000	/* HBI reference clock */
+#define HIFN_PLL_REF_CLK_PLL	0x00000001	/* PLL reference clock */
+#define HIFN_PLL_BP		0x00000002	/* Reference clock bypass */
+#define HIFN_PLL_PK_CLK_HBI	0x00000000	/* PK engine HBI clock */
+#define HIFN_PLL_PK_CLK_PLL	0x00000008	/* PK engine PLL clock */
+#define HIFN_PLL_PE_CLK_HBI	0x00000000	/* PE engine HBI clock */
+#define HIFN_PLL_PE_CLK_PLL	0x00000010	/* PE engine PLL clock */
+#define HIFN_PLL_RESERVED_1	0x00000400	/* Reserved bit, must be 1 */
+#define HIFN_PLL_ND_SHIFT	11		/* Clock multiplier shift */
+#define HIFN_PLL_ND_MULT_2	0x00000000	/* PLL clock multiplier 2 */
+#define HIFN_PLL_ND_MULT_4	0x00000800	/* PLL clock multiplier 4 */
+#define HIFN_PLL_ND_MULT_6	0x00001000	/* PLL clock multiplier 6 */
+#define HIFN_PLL_ND_MULT_8	0x00001800	/* PLL clock multiplier 8 */
+#define HIFN_PLL_ND_MULT_10	0x00002000	/* PLL clock multiplier 10 */
+#define HIFN_PLL_ND_MULT_12	0x00002800	/* PLL clock multiplier 12 */
+#define HIFN_PLL_IS_1_8		0x00000000	/* charge pump (mult. 1-8) */
+#define HIFN_PLL_IS_9_12	0x00010000	/* charge pump (mult. 9-12) */
+
+#define HIFN_PLL_FCK_MAX	266		/* Maximum PLL frequency */
+
+/* Public key reset register (HIFN_1_PUB_RESET) */
+#define	HIFN_PUBRST_RESET	0x00000001	/* reset public/rng unit */
+
+/* Public base address register (HIFN_1_PUB_BASE) */
+#define	HIFN_PUBBASE_ADDR	0x00003fff	/* base address */
+
+/* Public operand length register (HIFN_1_PUB_OPLEN) */
+#define	HIFN_PUBOPLEN_MOD_M	0x0000007f	/* modulus length mask */
+#define	HIFN_PUBOPLEN_MOD_S	0		/* modulus length shift */
+#define	HIFN_PUBOPLEN_EXP_M	0x0003ff80	/* exponent length mask */
+#define	HIFN_PUBOPLEN_EXP_S	7		/* exponent lenght shift */
+#define	HIFN_PUBOPLEN_RED_M	0x003c0000	/* reducend length mask */
+#define	HIFN_PUBOPLEN_RED_S	18		/* reducend length shift */
+
+/* Public operation register (HIFN_1_PUB_OP) */
+#define	HIFN_PUBOP_AOFFSET_M	0x0000007f	/* A offset mask */
+#define	HIFN_PUBOP_AOFFSET_S	0		/* A offset shift */
+#define	HIFN_PUBOP_BOFFSET_M	0x00000f80	/* B offset mask */
+#define	HIFN_PUBOP_BOFFSET_S	7		/* B offset shift */
+#define	HIFN_PUBOP_MOFFSET_M	0x0003f000	/* M offset mask */
+#define	HIFN_PUBOP_MOFFSET_S	12		/* M offset shift */
+#define	HIFN_PUBOP_OP_MASK	0x003c0000	/* Opcode: */
+#define	HIFN_PUBOP_OP_NOP	0x00000000	/*  NOP */
+#define	HIFN_PUBOP_OP_ADD	0x00040000	/*  ADD */
+#define	HIFN_PUBOP_OP_ADDC	0x00080000	/*  ADD w/carry */
+#define	HIFN_PUBOP_OP_SUB	0x000c0000	/*  SUB */
+#define	HIFN_PUBOP_OP_SUBC	0x00100000	/*  SUB w/carry */
+#define	HIFN_PUBOP_OP_MODADD	0x00140000	/*  Modular ADD */
+#define	HIFN_PUBOP_OP_MODSUB	0x00180000	/*  Modular SUB */
+#define	HIFN_PUBOP_OP_INCA	0x001c0000	/*  INC A */
+#define	HIFN_PUBOP_OP_DECA	0x00200000	/*  DEC A */
+#define	HIFN_PUBOP_OP_MULT	0x00240000	/*  MULT */
+#define	HIFN_PUBOP_OP_MODMULT	0x00280000	/*  Modular MULT */
+#define	HIFN_PUBOP_OP_MODRED	0x002c0000	/*  Modular RED */
+#define	HIFN_PUBOP_OP_MODEXP	0x00300000	/*  Modular EXP */
+
+/* Public status register (HIFN_1_PUB_STATUS) */
+#define	HIFN_PUBSTS_DONE	0x00000001	/* operation done */
+#define	HIFN_PUBSTS_CARRY	0x00000002	/* carry */
+
+/* Public interrupt enable register (HIFN_1_PUB_IEN) */
+#define	HIFN_PUBIEN_DONE	0x00000001	/* operation done interrupt */
+
+/* Random number generator config register (HIFN_1_RNG_CONFIG) */
+#define	HIFN_RNGCFG_ENA		0x00000001	/* enable rng */
+
+#define HIFN_NAMESIZE			32
+#define HIFN_MAX_RESULT_ORDER		5
+
+#define	HIFN_D_CMD_RSIZE		24*4
+#define	HIFN_D_SRC_RSIZE		80*4
+#define	HIFN_D_DST_RSIZE		80*4
+#define	HIFN_D_RES_RSIZE		24*4
+
+#define HIFN_QUEUE_LENGTH		HIFN_D_CMD_RSIZE-5
+
+#define AES_MIN_KEY_SIZE		16
+#define AES_MAX_KEY_SIZE		32
+
+#define HIFN_DES_KEY_LENGTH		8
+#define HIFN_3DES_KEY_LENGTH		24
+#define HIFN_MAX_CRYPT_KEY_LENGTH	AES_MAX_KEY_SIZE
+#define HIFN_IV_LENGTH			8
+#define HIFN_AES_IV_LENGTH		16
+#define	HIFN_MAX_IV_LENGTH		HIFN_AES_IV_LENGTH
+
+#define HIFN_MAC_KEY_LENGTH		64
+#define HIFN_MD5_LENGTH			16
+#define HIFN_SHA1_LENGTH		20
+#define HIFN_MAC_TRUNC_LENGTH		12
+
+#define	HIFN_MAX_COMMAND		(8 + 8 + 8 + 64 + 260)
+#define	HIFN_MAX_RESULT			(8 + 4 + 4 + 20 + 4)
+#define HIFN_USED_RESULT		12
+
+struct hifn_desc
+{
+	volatile u32		l;
+	volatile u32		p;
+};
+
+struct hifn_dma {
+	struct hifn_desc	cmdr[HIFN_D_CMD_RSIZE+1];
+	struct hifn_desc	srcr[HIFN_D_SRC_RSIZE+1];
+	struct hifn_desc	dstr[HIFN_D_DST_RSIZE+1];
+	struct hifn_desc	resr[HIFN_D_RES_RSIZE+1];
+
+	u8			command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND];
+	u8			result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT];
+
+	u64			test_src, test_dst;
+
+	/*
+	 *  Our current positions for insertion and removal from the descriptor
+	 *  rings.
+	 */
+	volatile int		cmdi, srci, dsti, resi;
+	volatile int		cmdu, srcu, dstu, resu;
+	int			cmdk, srck, dstk, resk;
+};
+
+#define HIFN_FLAG_CMD_BUSY	(1<<0)
+#define HIFN_FLAG_SRC_BUSY	(1<<1)
+#define HIFN_FLAG_DST_BUSY	(1<<2)
+#define HIFN_FLAG_RES_BUSY	(1<<3)
+#define HIFN_FLAG_OLD_KEY	(1<<4)
+
+#define HIFN_DEFAULT_ACTIVE_NUM	5
+
+struct hifn_device
+{
+	char			name[HIFN_NAMESIZE];
+
+	int			irq;
+
+	struct pci_dev		*pdev;
+	void __iomem		*bar[3];
+
+	unsigned long		result_mem;
+	dma_addr_t		dst;
+
+	void			*desc_virt;
+	dma_addr_t		desc_dma;
+
+	u32			dmareg;
+
+	void 			*sa[HIFN_D_RES_RSIZE];
+
+	spinlock_t		lock;
+
+	void 			*priv;
+
+	u32			flags;
+	int			active, started;
+	struct delayed_work	work;
+	unsigned long		reset;
+	unsigned long		success;
+	unsigned long		prev_success;
+
+	u8			snum;
+
+	struct tasklet_struct	tasklet;
+
+	struct crypto_queue 	queue;
+	struct list_head	alg_list;
+
+	unsigned int		pk_clk_freq;
+
+#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE)
+	unsigned int		rng_wait_time;
+	ktime_t			rngtime;
+	struct hwrng		rng;
+#endif
+};
+
+#define	HIFN_D_LENGTH			0x0000ffff
+#define	HIFN_D_NOINVALID		0x01000000
+#define	HIFN_D_MASKDONEIRQ		0x02000000
+#define	HIFN_D_DESTOVER			0x04000000
+#define	HIFN_D_OVER			0x08000000
+#define	HIFN_D_LAST			0x20000000
+#define	HIFN_D_JUMP			0x40000000
+#define	HIFN_D_VALID			0x80000000
+
+struct hifn_base_command
+{
+	volatile u16		masks;
+	volatile u16		session_num;
+	volatile u16		total_source_count;
+	volatile u16		total_dest_count;
+};
+
+#define	HIFN_BASE_CMD_COMP		0x0100	/* enable compression engine */
+#define	HIFN_BASE_CMD_PAD		0x0200	/* enable padding engine */
+#define	HIFN_BASE_CMD_MAC		0x0400	/* enable MAC engine */
+#define	HIFN_BASE_CMD_CRYPT		0x0800	/* enable crypt engine */
+#define	HIFN_BASE_CMD_DECODE		0x2000
+#define	HIFN_BASE_CMD_SRCLEN_M		0xc000
+#define	HIFN_BASE_CMD_SRCLEN_S		14
+#define	HIFN_BASE_CMD_DSTLEN_M		0x3000
+#define	HIFN_BASE_CMD_DSTLEN_S		12
+#define	HIFN_BASE_CMD_LENMASK_HI	0x30000
+#define	HIFN_BASE_CMD_LENMASK_LO	0x0ffff
+
+/*
+ * Structure to help build up the command data structure.
+ */
+struct hifn_crypt_command
+{
+	volatile u16 		masks;
+	volatile u16 		header_skip;
+	volatile u16 		source_count;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_CRYPT_CMD_ALG_MASK		0x0003		/* algorithm: */
+#define	HIFN_CRYPT_CMD_ALG_DES		0x0000		/*   DES */
+#define	HIFN_CRYPT_CMD_ALG_3DES		0x0001		/*   3DES */
+#define	HIFN_CRYPT_CMD_ALG_RC4		0x0002		/*   RC4 */
+#define	HIFN_CRYPT_CMD_ALG_AES		0x0003		/*   AES */
+#define	HIFN_CRYPT_CMD_MODE_MASK	0x0018		/* Encrypt mode: */
+#define	HIFN_CRYPT_CMD_MODE_ECB		0x0000		/*   ECB */
+#define	HIFN_CRYPT_CMD_MODE_CBC		0x0008		/*   CBC */
+#define	HIFN_CRYPT_CMD_MODE_CFB		0x0010		/*   CFB */
+#define	HIFN_CRYPT_CMD_MODE_OFB		0x0018		/*   OFB */
+#define	HIFN_CRYPT_CMD_CLR_CTX		0x0040		/* clear context */
+#define	HIFN_CRYPT_CMD_KSZ_MASK		0x0600		/* AES key size: */
+#define	HIFN_CRYPT_CMD_KSZ_128		0x0000		/*  128 bit */
+#define	HIFN_CRYPT_CMD_KSZ_192		0x0200		/*  192 bit */
+#define	HIFN_CRYPT_CMD_KSZ_256		0x0400		/*  256 bit */
+#define	HIFN_CRYPT_CMD_NEW_KEY		0x0800		/* expect new key */
+#define	HIFN_CRYPT_CMD_NEW_IV		0x1000		/* expect new iv */
+#define	HIFN_CRYPT_CMD_SRCLEN_M		0xc000
+#define	HIFN_CRYPT_CMD_SRCLEN_S		14
+
+/*
+ * Structure to help build up the command data structure.
+ */
+struct hifn_mac_command
+{
+	volatile u16 		masks;
+	volatile u16 		header_skip;
+	volatile u16 		source_count;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_MAC_CMD_ALG_MASK		0x0001
+#define	HIFN_MAC_CMD_ALG_SHA1		0x0000
+#define	HIFN_MAC_CMD_ALG_MD5		0x0001
+#define	HIFN_MAC_CMD_MODE_MASK		0x000c
+#define	HIFN_MAC_CMD_MODE_HMAC		0x0000
+#define	HIFN_MAC_CMD_MODE_SSL_MAC	0x0004
+#define	HIFN_MAC_CMD_MODE_HASH		0x0008
+#define	HIFN_MAC_CMD_MODE_FULL		0x0004
+#define	HIFN_MAC_CMD_TRUNC		0x0010
+#define	HIFN_MAC_CMD_RESULT		0x0020
+#define	HIFN_MAC_CMD_APPEND		0x0040
+#define	HIFN_MAC_CMD_SRCLEN_M		0xc000
+#define	HIFN_MAC_CMD_SRCLEN_S		14
+
+/*
+ * MAC POS IPsec initiates authentication after encryption on encodes
+ * and before decryption on decodes.
+ */
+#define	HIFN_MAC_CMD_POS_IPSEC		0x0200
+#define	HIFN_MAC_CMD_NEW_KEY		0x0800
+
+struct hifn_comp_command
+{
+	volatile u16 		masks;
+	volatile u16 		header_skip;
+	volatile u16 		source_count;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_COMP_CMD_SRCLEN_M		0xc000
+#define	HIFN_COMP_CMD_SRCLEN_S		14
+#define	HIFN_COMP_CMD_ONE		0x0100	/* must be one */
+#define	HIFN_COMP_CMD_CLEARHIST		0x0010	/* clear history */
+#define	HIFN_COMP_CMD_UPDATEHIST	0x0008	/* update history */
+#define	HIFN_COMP_CMD_LZS_STRIP0	0x0004	/* LZS: strip zero */
+#define	HIFN_COMP_CMD_MPPC_RESTART	0x0004	/* MPPC: restart */
+#define	HIFN_COMP_CMD_ALG_MASK		0x0001	/* compression mode: */
+#define	HIFN_COMP_CMD_ALG_MPPC		0x0001	/*   MPPC */
+#define	HIFN_COMP_CMD_ALG_LZS		0x0000	/*   LZS */
+
+struct hifn_base_result
+{
+	volatile u16 		flags;
+	volatile u16 		session;
+	volatile u16 		src_cnt;		/* 15:0 of source count */
+	volatile u16 		dst_cnt;		/* 15:0 of dest count */
+};
+
+#define	HIFN_BASE_RES_DSTOVERRUN	0x0200	/* destination overrun */
+#define	HIFN_BASE_RES_SRCLEN_M		0xc000	/* 17:16 of source count */
+#define	HIFN_BASE_RES_SRCLEN_S		14
+#define	HIFN_BASE_RES_DSTLEN_M		0x3000	/* 17:16 of dest count */
+#define	HIFN_BASE_RES_DSTLEN_S		12
+
+struct hifn_comp_result
+{
+	volatile u16 		flags;
+	volatile u16 		crc;
+};
+
+#define	HIFN_COMP_RES_LCB_M		0xff00	/* longitudinal check byte */
+#define	HIFN_COMP_RES_LCB_S		8
+#define	HIFN_COMP_RES_RESTART		0x0004	/* MPPC: restart */
+#define	HIFN_COMP_RES_ENDMARKER		0x0002	/* LZS: end marker seen */
+#define	HIFN_COMP_RES_SRC_NOTZERO	0x0001	/* source expired */
+
+struct hifn_mac_result
+{
+	volatile u16 		flags;
+	volatile u16 		reserved;
+	/* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */
+};
+
+#define	HIFN_MAC_RES_MISCOMPARE		0x0002	/* compare failed */
+#define	HIFN_MAC_RES_SRC_NOTZERO	0x0001	/* source expired */
+
+struct hifn_crypt_result
+{
+	volatile u16 		flags;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_CRYPT_RES_SRC_NOTZERO	0x0001	/* source expired */
+
+#ifndef HIFN_POLL_FREQUENCY
+#define	HIFN_POLL_FREQUENCY	0x1
+#endif
+
+#ifndef HIFN_POLL_SCALAR
+#define	HIFN_POLL_SCALAR	0x0
+#endif
+
+#define	HIFN_MAX_SEGLEN 	0xffff		/* maximum dma segment len */
+#define	HIFN_MAX_DMALEN		0x3ffff		/* maximum dma length */
+
+struct hifn_crypto_alg
+{
+	struct list_head	entry;
+	struct crypto_alg	alg;
+	struct hifn_device	*dev;
+};
+
+#define ASYNC_SCATTERLIST_CACHE	16
+
+#define ASYNC_FLAGS_MISALIGNED	(1<<0)
+
+struct ablkcipher_walk
+{
+	struct scatterlist	cache[ASYNC_SCATTERLIST_CACHE];
+	u32			flags;
+	int			num;
+};
+
+struct hifn_context
+{
+	u8			key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv;
+	struct hifn_device	*dev;
+	unsigned int		keysize, ivsize;
+	u8			op, type, mode, unused;
+	struct ablkcipher_walk	walk;
+	atomic_t		sg_num;
+};
+
+#define crypto_alg_to_hifn(a)	container_of(a, struct hifn_crypto_alg, alg)
+
+static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg)
+{
+	u32 ret;
+
+	ret = readl((char *)(dev->bar[0]) + reg);
+
+	return ret;
+}
+
+static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg)
+{
+	u32 ret;
+
+	ret = readl((char *)(dev->bar[1]) + reg);
+
+	return ret;
+}
+
+static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
+{
+	writel(val, (char *)(dev->bar[0]) + reg);
+}
+
+static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
+{
+	writel(val, (char *)(dev->bar[1]) + reg);
+}
+
+static void hifn_wait_puc(struct hifn_device *dev)
+{
+	int i;
+	u32 ret;
+
+	for (i=10000; i > 0; --i) {
+		ret = hifn_read_0(dev, HIFN_0_PUCTRL);
+		if (!(ret & HIFN_PUCTRL_RESET))
+			break;
+
+		udelay(1);
+	}
+
+	if (!i)
+		dprintk("%s: Failed to reset PUC unit.\n", dev->name);
+}
+
+static void hifn_reset_puc(struct hifn_device *dev)
+{
+	hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
+	hifn_wait_puc(dev);
+}
+
+static void hifn_stop_device(struct hifn_device *dev)
+{
+	hifn_write_1(dev, HIFN_1_DMA_CSR,
+		HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
+		HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS);
+	hifn_write_0(dev, HIFN_0_PUIER, 0);
+	hifn_write_1(dev, HIFN_1_DMA_IER, 0);
+}
+
+static void hifn_reset_dma(struct hifn_device *dev, int full)
+{
+	hifn_stop_device(dev);
+
+	/*
+	 * Setting poll frequency and others to 0.
+	 */
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+			HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+	mdelay(1);
+
+	/*
+	 * Reset DMA.
+	 */
+	if (full) {
+		hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
+		mdelay(1);
+	} else {
+		hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE |
+				HIFN_DMACNFG_MSTRESET);
+		hifn_reset_puc(dev);
+	}
+
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+			HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+
+	hifn_reset_puc(dev);
+}
+
+static u32 hifn_next_signature(u_int32_t a, u_int cnt)
+{
+	int i;
+	u32 v;
+
+	for (i = 0; i < cnt; i++) {
+
+		/* get the parity */
+		v = a & 0x80080125;
+		v ^= v >> 16;
+		v ^= v >> 8;
+		v ^= v >> 4;
+		v ^= v >> 2;
+		v ^= v >> 1;
+
+		a = (v & 1) ^ (a << 1);
+	}
+
+	return a;
+}
+
+static struct pci2id {
+	u_short		pci_vendor;
+	u_short		pci_prod;
+	char		card_id[13];
+} pci2id[] = {
+	{
+		PCI_VENDOR_ID_HIFN,
+		PCI_DEVICE_ID_HIFN_7955,
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00 }
+	},
+	{
+		PCI_VENDOR_ID_HIFN,
+		PCI_DEVICE_ID_HIFN_7956,
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00 }
+	}
+};
+
+#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE)
+static int hifn_rng_data_present(struct hwrng *rng, int wait)
+{
+	struct hifn_device *dev = (struct hifn_device *)rng->priv;
+	s64 nsec;
+
+	nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime));
+	nsec -= dev->rng_wait_time;
+	if (nsec <= 0)
+		return 1;
+	if (!wait)
+		return 0;
+	ndelay(nsec);
+	return 1;
+}
+
+static int hifn_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	struct hifn_device *dev = (struct hifn_device *)rng->priv;
+
+	*data = hifn_read_1(dev, HIFN_1_RNG_DATA);
+	dev->rngtime = ktime_get();
+	return 4;
+}
+
+static int hifn_register_rng(struct hifn_device *dev)
+{
+	/*
+	 * We must wait at least 256 Pk_clk cycles between two reads of the rng.
+	 */
+	dev->rng_wait_time	= DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) *
+				  256;
+
+	dev->rng.name		= dev->name;
+	dev->rng.data_present	= hifn_rng_data_present,
+	dev->rng.data_read	= hifn_rng_data_read,
+	dev->rng.priv		= (unsigned long)dev;
+
+	return hwrng_register(&dev->rng);
+}
+
+static void hifn_unregister_rng(struct hifn_device *dev)
+{
+	hwrng_unregister(&dev->rng);
+}
+#else
+#define hifn_register_rng(dev)		0
+#define hifn_unregister_rng(dev)
+#endif
+
+static int hifn_init_pubrng(struct hifn_device *dev)
+{
+	int i;
+
+	hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) |
+			HIFN_PUBRST_RESET);
+
+	for (i=100; i > 0; --i) {
+		mdelay(1);
+
+		if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0)
+			break;
+	}
+
+	if (!i)
+		dprintk("Chip %s: Failed to initialise public key engine.\n",
+				dev->name);
+	else {
+		hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE);
+		dev->dmareg |= HIFN_DMAIER_PUBDONE;
+		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+
+		dprintk("Chip %s: Public key engine has been sucessfully "
+				"initialised.\n", dev->name);
+	}
+
+	/*
+	 * Enable RNG engine.
+	 */
+
+	hifn_write_1(dev, HIFN_1_RNG_CONFIG,
+			hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA);
+	dprintk("Chip %s: RNG engine has been successfully initialised.\n",
+			dev->name);
+
+#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE)
+	/* First value must be discarded */
+	hifn_read_1(dev, HIFN_1_RNG_DATA);
+	dev->rngtime = ktime_get();
+#endif
+	return 0;
+}
+
+static int hifn_enable_crypto(struct hifn_device *dev)
+{
+	u32 dmacfg, addr;
+	char *offtbl = NULL;
+	int i;
+
+	for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) {
+		if (pci2id[i].pci_vendor == dev->pdev->vendor &&
+				pci2id[i].pci_prod == dev->pdev->device) {
+			offtbl = pci2id[i].card_id;
+			break;
+		}
+	}
+
+	if (offtbl == NULL) {
+		dprintk("Chip %s: Unknown card!\n", dev->name);
+		return -ENODEV;
+	}
+
+	dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG);
+
+	hifn_write_1(dev, HIFN_1_DMA_CNFG,
+			HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET |
+			HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+	mdelay(1);
+	addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1);
+	mdelay(1);
+	hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0);
+	mdelay(1);
+
+	for (i=0; i<12; ++i) {
+		addr = hifn_next_signature(addr, offtbl[i] + 0x101);
+		hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr);
+
+		mdelay(1);
+	}
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg);
+
+	dprintk("Chip %s: %s.\n", dev->name, pci_name(dev->pdev));
+
+	return 0;
+}
+
+static void hifn_init_dma(struct hifn_device *dev)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	u32 dptr = dev->desc_dma;
+	int i;
+
+	for (i=0; i<HIFN_D_CMD_RSIZE; ++i)
+		dma->cmdr[i].p = __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, command_bufs[i][0]));
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i)
+		dma->resr[i].p = __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, result_bufs[i][0]));
+
+	/*
+	 * Setup LAST descriptors.
+	 */
+	dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, cmdr[0]));
+	dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, srcr[0]));
+	dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, dstr[0]));
+	dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, resr[0]));
+
+	dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0;
+	dma->cmdi = dma->srci = dma->dsti = dma->resi = 0;
+	dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
+}
+
+/*
+ * Initialize the PLL. We need to know the frequency of the reference clock
+ * to calculate the optimal multiplier. For PCI we assume 66MHz, since that
+ * allows us to operate without the risk of overclocking the chip. If it
+ * actually uses 33MHz, the chip will operate at half the speed, this can be
+ * overriden by specifying the frequency as module parameter (pci33).
+ *
+ * Unfortunately the PCI clock is not very suitable since the HIFN needs a
+ * stable clock and the PCI clock frequency may vary, so the default is the
+ * external clock. There is no way to find out its frequency, we default to
+ * 66MHz since according to Mike Ham of HiFn, almost every board in existence
+ * has an external crystal populated at 66MHz.
+ */
+static void hifn_init_pll(struct hifn_device *dev)
+{
+	unsigned int freq, m;
+	u32 pllcfg;
+
+	pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1;
+
+	if (strncmp(hifn_pll_ref, "ext", 3) == 0)
+		pllcfg |= HIFN_PLL_REF_CLK_PLL;
+	else
+		pllcfg |= HIFN_PLL_REF_CLK_HBI;
+
+	if (hifn_pll_ref[3] != '\0')
+		freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
+	else {
+		freq = 66;
+		printk(KERN_INFO "hifn795x: assuming %uMHz clock speed, "
+				 "override with hifn_pll_ref=%.3s<frequency>\n",
+		       freq, hifn_pll_ref);
+	}
+
+	m = HIFN_PLL_FCK_MAX / freq;
+
+	pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT;
+	if (m <= 8)
+		pllcfg |= HIFN_PLL_IS_1_8;
+	else
+		pllcfg |= HIFN_PLL_IS_9_12;
+
+	/* Select clock source and enable clock bypass */
+	hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+		     HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP);
+
+	/* Let the chip lock to the input clock */
+	mdelay(10);
+
+	/* Disable clock bypass */
+	hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+		     HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI);
+
+	/* Switch the engines to the PLL */
+	hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+		     HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL);
+
+	/*
+	 * The Fpk_clk runs at half the total speed. Its frequency is needed to
+	 * calculate the minimum time between two reads of the rng. Since 33MHz
+	 * is actually 33.333... we overestimate the frequency here, resulting
+	 * in slightly larger intervals.
+	 */
+	dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2;
+}
+
+static void hifn_init_registers(struct hifn_device *dev)
+{
+	u32 dptr = dev->desc_dma;
+
+	/* Initialization magic... */
+	hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
+	hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD);
+	hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
+
+	/* write all 4 ring address registers */
+	hifn_write_1(dev, HIFN_1_DMA_CRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, cmdr[0])));
+	hifn_write_1(dev, HIFN_1_DMA_SRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, srcr[0])));
+	hifn_write_1(dev, HIFN_1_DMA_DRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, dstr[0])));
+	hifn_write_1(dev, HIFN_1_DMA_RRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, resr[0])));
+
+	mdelay(2);
+#if 0
+	hifn_write_1(dev, HIFN_1_DMA_CSR,
+	    HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
+	    HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS |
+	    HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
+	    HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
+	    HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
+	    HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
+	    HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
+	    HIFN_DMACSR_S_WAIT |
+	    HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
+	    HIFN_DMACSR_C_WAIT |
+	    HIFN_DMACSR_ENGINE |
+	    HIFN_DMACSR_PUBDONE);
+#else
+	hifn_write_1(dev, HIFN_1_DMA_CSR,
+	    HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
+	    HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA |
+	    HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
+	    HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
+	    HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
+	    HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
+	    HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
+	    HIFN_DMACSR_S_WAIT |
+	    HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
+	    HIFN_DMACSR_C_WAIT |
+	    HIFN_DMACSR_ENGINE |
+	    HIFN_DMACSR_PUBDONE);
+#endif
+	hifn_read_1(dev, HIFN_1_DMA_CSR);
+
+	dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT |
+	    HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER |
+	    HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT |
+	    HIFN_DMAIER_ENGINE;
+	dev->dmareg &= ~HIFN_DMAIER_C_WAIT;
+
+	hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+	hifn_read_1(dev, HIFN_1_DMA_IER);
+#if 0
+	hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG |
+		    HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES |
+		    HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 |
+		    HIFN_PUCNFG_DRAM);
+#else
+	hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342);
+#endif
+	hifn_init_pll(dev);
+
+	hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+	    HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST |
+	    ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) |
+	    ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL));
+}
+
+static int hifn_setup_base_command(struct hifn_device *dev, u8 *buf,
+		unsigned dlen, unsigned slen, u16 mask, u8 snum)
+{
+	struct hifn_base_command *base_cmd;
+	u8 *buf_pos = buf;
+
+	base_cmd = (struct hifn_base_command *)buf_pos;
+	base_cmd->masks = __cpu_to_le16(mask);
+	base_cmd->total_source_count =
+		__cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO);
+	base_cmd->total_dest_count =
+		__cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO);
+
+	dlen >>= 16;
+	slen >>= 16;
+	base_cmd->session_num = __cpu_to_le16(snum |
+	    ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) |
+	    ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M));
+
+	return sizeof(struct hifn_base_command);
+}
+
+static int hifn_setup_crypto_command(struct hifn_device *dev,
+		u8 *buf, unsigned dlen, unsigned slen,
+		u8 *key, int keylen, u8 *iv, int ivsize, u16 mode)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	struct hifn_crypt_command *cry_cmd;
+	u8 *buf_pos = buf;
+	u16 cmd_len;
+
+	cry_cmd = (struct hifn_crypt_command *)buf_pos;
+
+	cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff);
+	dlen >>= 16;
+	cry_cmd->masks = __cpu_to_le16(mode |
+			((dlen << HIFN_CRYPT_CMD_SRCLEN_S) &
+			 HIFN_CRYPT_CMD_SRCLEN_M));
+	cry_cmd->header_skip = 0;
+	cry_cmd->reserved = 0;
+
+	buf_pos += sizeof(struct hifn_crypt_command);
+
+	dma->cmdu++;
+	if (dma->cmdu > 1) {
+		dev->dmareg |= HIFN_DMAIER_C_WAIT;
+		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+	}
+
+	if (keylen) {
+		memcpy(buf_pos, key, keylen);
+		buf_pos += keylen;
+	}
+	if (ivsize) {
+		memcpy(buf_pos, iv, ivsize);
+		buf_pos += ivsize;
+	}
+
+	cmd_len = buf_pos - buf;
+
+	return cmd_len;
+}
+
+static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
+		unsigned int offset, unsigned int size)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int idx;
+	dma_addr_t addr;
+
+	addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE);
+
+	idx = dma->srci;
+
+	dma->srcr[idx].p = __cpu_to_le32(addr);
+	dma->srcr[idx].l = __cpu_to_le32(size) | HIFN_D_VALID |
+			HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST;
+
+	if (++idx == HIFN_D_SRC_RSIZE) {
+		dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+				HIFN_D_JUMP |
+				HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+		idx = 0;
+	}
+
+	dma->srci = idx;
+	dma->srcu++;
+
+	if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_SRC_BUSY;
+	}
+
+	return size;
+}
+
+static void hifn_setup_res_desc(struct hifn_device *dev)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+	dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT |
+			HIFN_D_VALID | HIFN_D_LAST);
+	/*
+	 * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID |
+	 *					HIFN_D_LAST | HIFN_D_NOINVALID);
+	 */
+
+	if (++dma->resi == HIFN_D_RES_RSIZE) {
+		dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID |
+				HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+		dma->resi = 0;
+	}
+
+	dma->resu++;
+
+	if (!(dev->flags & HIFN_FLAG_RES_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_RES_BUSY;
+	}
+}
+
+static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
+		unsigned offset, unsigned size)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int idx;
+	dma_addr_t addr;
+
+	addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE);
+
+	idx = dma->dsti;
+	dma->dstr[idx].p = __cpu_to_le32(addr);
+	dma->dstr[idx].l = __cpu_to_le32(size |	HIFN_D_VALID |
+			HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST);
+
+	if (++idx == HIFN_D_DST_RSIZE) {
+		dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+				HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
+				HIFN_D_LAST | HIFN_D_NOINVALID);
+		idx = 0;
+	}
+	dma->dsti = idx;
+	dma->dstu++;
+
+	if (!(dev->flags & HIFN_FLAG_DST_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_DST_BUSY;
+	}
+}
+
+static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff,
+		struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv,
+		struct hifn_context *ctx)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int cmd_len, sa_idx;
+	u8 *buf, *buf_pos;
+	u16 mask;
+
+	dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n",
+			dev->name, spage, soff, dpage, doff, nbytes, priv, ctx);
+
+	sa_idx = dma->resi;
+
+	hifn_setup_src_desc(dev, spage, soff, nbytes);
+
+	buf_pos = buf = dma->command_bufs[dma->cmdi];
+
+	mask = 0;
+	switch (ctx->op) {
+		case ACRYPTO_OP_DECRYPT:
+			mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE;
+			break;
+		case ACRYPTO_OP_ENCRYPT:
+			mask = HIFN_BASE_CMD_CRYPT;
+			break;
+		case ACRYPTO_OP_HMAC:
+			mask = HIFN_BASE_CMD_MAC;
+			break;
+		default:
+			goto err_out;
+	}
+
+	buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes,
+			nbytes, mask, dev->snum);
+
+	if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) {
+		u16 md = 0;
+
+		if (ctx->keysize)
+			md |= HIFN_CRYPT_CMD_NEW_KEY;
+		if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB)
+			md |= HIFN_CRYPT_CMD_NEW_IV;
+
+		switch (ctx->mode) {
+			case ACRYPTO_MODE_ECB:
+				md |= HIFN_CRYPT_CMD_MODE_ECB;
+				break;
+			case ACRYPTO_MODE_CBC:
+				md |= HIFN_CRYPT_CMD_MODE_CBC;
+				break;
+			case ACRYPTO_MODE_CFB:
+				md |= HIFN_CRYPT_CMD_MODE_CFB;
+				break;
+			case ACRYPTO_MODE_OFB:
+				md |= HIFN_CRYPT_CMD_MODE_OFB;
+				break;
+			default:
+				goto err_out;
+		}
+
+		switch (ctx->type) {
+			case ACRYPTO_TYPE_AES_128:
+				if (ctx->keysize != 16)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_KSZ_128 |
+					HIFN_CRYPT_CMD_ALG_AES;
+				break;
+			case ACRYPTO_TYPE_AES_192:
+				if (ctx->keysize != 24)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_KSZ_192 |
+					HIFN_CRYPT_CMD_ALG_AES;
+				break;
+			case ACRYPTO_TYPE_AES_256:
+				if (ctx->keysize != 32)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_KSZ_256 |
+					HIFN_CRYPT_CMD_ALG_AES;
+				break;
+			case ACRYPTO_TYPE_3DES:
+				if (ctx->keysize != 24)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_ALG_3DES;
+				break;
+			case ACRYPTO_TYPE_DES:
+				if (ctx->keysize != 8)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_ALG_DES;
+				break;
+			default:
+				goto err_out;
+		}
+
+		buf_pos += hifn_setup_crypto_command(dev, buf_pos,
+				nbytes, nbytes, ctx->key, ctx->keysize,
+				ctx->iv, ctx->ivsize, md);
+	}
+
+	dev->sa[sa_idx] = priv;
+
+	cmd_len = buf_pos - buf;
+	dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID |
+			HIFN_D_LAST | HIFN_D_MASKDONEIRQ);
+
+	if (++dma->cmdi == HIFN_D_CMD_RSIZE) {
+		dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND |
+			HIFN_D_VALID | HIFN_D_LAST |
+			HIFN_D_MASKDONEIRQ | HIFN_D_JUMP);
+		dma->cmdi = 0;
+	} else
+		dma->cmdr[dma->cmdi-1].l |= __cpu_to_le32(HIFN_D_VALID);
+
+	if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_CMD_BUSY;
+	}
+
+	hifn_setup_dst_desc(dev, dpage, doff, nbytes);
+	hifn_setup_res_desc(dev);
+
+	return 0;
+
+err_out:
+	return -EINVAL;
+}
+
+static int ablkcipher_walk_init(struct ablkcipher_walk *w,
+		int num, gfp_t gfp_flags)
+{
+	int i;
+
+	num = min(ASYNC_SCATTERLIST_CACHE, num);
+	sg_init_table(w->cache, num);
+
+	w->num = 0;
+	for (i=0; i<num; ++i) {
+		struct page *page = alloc_page(gfp_flags);
+		struct scatterlist *s;
+
+		if (!page)
+			break;
+
+		s = &w->cache[i];
+
+		sg_set_page(s, page, PAGE_SIZE, 0);
+		w->num++;
+	}
+
+	return i;
+}
+
+static void ablkcipher_walk_exit(struct ablkcipher_walk *w)
+{
+	int i;
+
+	for (i=0; i<w->num; ++i) {
+		struct scatterlist *s = &w->cache[i];
+
+		__free_page(sg_page(s));
+
+		s->length = 0;
+	}
+
+	w->num = 0;
+}
+
+static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src,
+		unsigned int size, unsigned int *nbytesp)
+{
+	unsigned int copy, drest = *drestp, nbytes = *nbytesp;
+	int idx = 0;
+	void *saddr;
+
+	if (drest < size || size > nbytes)
+		return -EINVAL;
+
+	while (size) {
+		copy = min(drest, src->length);
+
+		saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1);
+		memcpy(daddr, saddr + src->offset, copy);
+		kunmap_atomic(saddr, KM_SOFTIRQ1);
+
+		size -= copy;
+		drest -= copy;
+		nbytes -= copy;
+		daddr += copy;
+
+		dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n",
+				__func__, copy, size, drest, nbytes);
+
+		src++;
+		idx++;
+	}
+
+	*nbytesp = nbytes;
+	*drestp = drest;
+
+	return idx;
+}
+
+static int ablkcipher_walk(struct ablkcipher_request *req,
+		struct ablkcipher_walk *w)
+{
+	unsigned blocksize =
+		crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
+	unsigned alignmask =
+		crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
+	struct scatterlist *src, *dst, *t;
+	void *daddr;
+	unsigned int nbytes = req->nbytes, offset, copy, diff;
+	int idx, tidx, err;
+
+	tidx = idx = 0;
+	offset = 0;
+	while (nbytes) {
+		if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED))
+			return -EINVAL;
+
+		src = &req->src[idx];
+		dst = &req->dst[idx];
+
+		dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, "
+				"blocksize: %u, nbytes: %u.\n",
+				__func__, src->length, dst->length, src->offset,
+				dst->offset, offset, blocksize, nbytes);
+
+		if (src->length & (blocksize - 1) ||
+				src->offset & (alignmask - 1) ||
+				dst->length & (blocksize - 1) ||
+				dst->offset & (alignmask - 1) ||
+				offset) {
+			unsigned slen = src->length - offset;
+			unsigned dlen = PAGE_SIZE;
+
+			t = &w->cache[idx];
+
+			daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0);
+			err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes);
+			if (err < 0)
+				goto err_out_unmap;
+
+			idx += err;
+
+			copy = slen & ~(blocksize - 1);
+			diff = slen & (blocksize - 1);
+
+			if (dlen < nbytes) {
+				/*
+				 * Destination page does not have enough space
+				 * to put there additional blocksized chunk,
+				 * so we mark that page as containing only
+				 * blocksize aligned chunks:
+				 * 	t->length = (slen & ~(blocksize - 1));
+				 * and increase number of bytes to be processed
+				 * in next chunk:
+				 * 	nbytes += diff;
+				 */
+				nbytes += diff;
+
+				/*
+				 * Temporary of course...
+				 * Kick author if you will catch this one.
+				 */
+				printk(KERN_ERR "%s: dlen: %u, nbytes: %u,"
+					"slen: %u, offset: %u.\n",
+					__func__, dlen, nbytes, slen, offset);
+				printk(KERN_ERR "%s: please contact author to fix this "
+					"issue, generally you should not catch "
+					"this path under any condition but who "
+					"knows how did you use crypto code.\n"
+					"Thank you.\n",	__func__);
+				BUG();
+			} else {
+				copy += diff + nbytes;
+
+				src = &req->src[idx];
+
+				err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes);
+				if (err < 0)
+					goto err_out_unmap;
+
+				idx += err;
+			}
+
+			t->length = copy;
+			t->offset = offset;
+
+			kunmap_atomic(daddr, KM_SOFTIRQ0);
+		} else {
+			nbytes -= src->length;
+			idx++;
+		}
+
+		tidx++;
+	}
+
+	return tidx;
+
+err_out_unmap:
+	kunmap_atomic(daddr, KM_SOFTIRQ0);
+	return err;
+}
+
+static int hifn_setup_session(struct ablkcipher_request *req)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev = ctx->dev;
+	struct page *spage, *dpage;
+	unsigned long soff, doff, flags;
+	unsigned int nbytes = req->nbytes, idx = 0, len;
+	int err = -EINVAL, sg_num;
+	struct scatterlist *src, *dst, *t;
+	unsigned blocksize =
+		crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
+	unsigned alignmask =
+		crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
+
+	if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB)
+		goto err_out_exit;
+
+	ctx->walk.flags = 0;
+
+	while (nbytes) {
+		src = &req->src[idx];
+		dst = &req->dst[idx];
+
+		if (src->length & (blocksize - 1) ||
+				src->offset & (alignmask - 1) ||
+				dst->length & (blocksize - 1) ||
+				dst->offset & (alignmask - 1)) {
+			ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED;
+		}
+
+		nbytes -= src->length;
+		idx++;
+	}
+
+	if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+		err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC);
+		if (err < 0)
+			return err;
+	}
+
+	nbytes = req->nbytes;
+	idx = 0;
+
+	sg_num = ablkcipher_walk(req, &ctx->walk);
+
+	atomic_set(&ctx->sg_num, sg_num);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->started + sg_num > HIFN_QUEUE_LENGTH) {
+		err = -EAGAIN;
+		goto err_out;
+	}
+
+	dev->snum++;
+	dev->started += sg_num;
+
+	while (nbytes) {
+		src = &req->src[idx];
+		dst = &req->dst[idx];
+		t = &ctx->walk.cache[idx];
+
+		if (t->length) {
+			spage = dpage = sg_page(t);
+			soff = doff = 0;
+			len = t->length;
+		} else {
+			spage = sg_page(src);
+			soff = src->offset;
+
+			dpage = sg_page(dst);
+			doff = dst->offset;
+
+			len = dst->length;
+		}
+
+		idx++;
+
+		err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes,
+				req, ctx);
+		if (err)
+			goto err_out;
+
+		nbytes -= len;
+	}
+
+	dev->active = HIFN_DEFAULT_ACTIVE_NUM;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+
+err_out:
+	spin_unlock_irqrestore(&dev->lock, flags);
+err_out_exit:
+	if (err && printk_ratelimit())
+		dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
+				"type: %u, err: %d.\n",
+			dev->name, ctx->iv, ctx->ivsize,
+			ctx->key, ctx->keysize,
+			ctx->mode, ctx->op, ctx->type, err);
+
+	return err;
+}
+
+static int hifn_test(struct hifn_device *dev, int encdec, u8 snum)
+{
+	int n, err;
+	u8 src[16];
+	struct hifn_context ctx;
+	u8 fips_aes_ecb_from_zero[16] = {
+		0x66, 0xE9, 0x4B, 0xD4,
+		0xEF, 0x8A, 0x2C, 0x3B,
+		0x88, 0x4C, 0xFA, 0x59,
+		0xCA, 0x34, 0x2B, 0x2E};
+
+	memset(src, 0, sizeof(src));
+	memset(ctx.key, 0, sizeof(ctx.key));
+
+	ctx.dev = dev;
+	ctx.keysize = 16;
+	ctx.ivsize = 0;
+	ctx.iv = NULL;
+	ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT;
+	ctx.mode = ACRYPTO_MODE_ECB;
+	ctx.type = ACRYPTO_TYPE_AES_128;
+	atomic_set(&ctx.sg_num, 1);
+
+	err = hifn_setup_dma(dev,
+			virt_to_page(src), offset_in_page(src),
+			virt_to_page(src), offset_in_page(src),
+			sizeof(src), NULL, &ctx);
+	if (err)
+		goto err_out;
+
+	msleep(200);
+
+	dprintk("%s: decoded: ", dev->name);
+	for (n=0; n<sizeof(src); ++n)
+		dprintk("%02x ", src[n]);
+	dprintk("\n");
+	dprintk("%s: FIPS   : ", dev->name);
+	for (n=0; n<sizeof(fips_aes_ecb_from_zero); ++n)
+		dprintk("%02x ", fips_aes_ecb_from_zero[n]);
+	dprintk("\n");
+
+	if (!memcmp(src, fips_aes_ecb_from_zero, sizeof(fips_aes_ecb_from_zero))) {
+		printk(KERN_INFO "%s: AES 128 ECB test has been successfully "
+				"passed.\n", dev->name);
+		return 0;
+	}
+
+err_out:
+	printk(KERN_INFO "%s: AES 128 ECB test has been failed.\n", dev->name);
+	return -1;
+}
+
+static int hifn_start_device(struct hifn_device *dev)
+{
+	int err;
+
+	hifn_reset_dma(dev, 1);
+
+	err = hifn_enable_crypto(dev);
+	if (err)
+		return err;
+
+	hifn_reset_puc(dev);
+
+	hifn_init_dma(dev);
+
+	hifn_init_registers(dev);
+
+	hifn_init_pubrng(dev);
+
+	return 0;
+}
+
+static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset,
+		struct scatterlist *dst, unsigned int size, unsigned int *nbytesp)
+{
+	unsigned int srest = *srestp, nbytes = *nbytesp, copy;
+	void *daddr;
+	int idx = 0;
+
+	if (srest < size || size > nbytes)
+		return -EINVAL;
+
+	while (size) {
+
+		copy = min(dst->length, srest);
+
+		daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
+		memcpy(daddr + dst->offset + offset, saddr, copy);
+		kunmap_atomic(daddr, KM_IRQ0);
+
+		nbytes -= copy;
+		size -= copy;
+		srest -= copy;
+		saddr += copy;
+		offset = 0;
+
+		dprintk("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n",
+				__func__, copy, size, srest, nbytes);
+
+		dst++;
+		idx++;
+	}
+
+	*nbytesp = nbytes;
+	*srestp = srest;
+
+	return idx;
+}
+
+static void hifn_process_ready(struct ablkcipher_request *req, int error)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev;
+
+	dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx);
+
+	dev = ctx->dev;
+	dprintk("%s: req: %p, started: %d, sg_num: %d.\n",
+		__func__, req, dev->started, atomic_read(&ctx->sg_num));
+
+	if (--dev->started < 0)
+		BUG();
+
+	if (atomic_dec_and_test(&ctx->sg_num)) {
+		unsigned int nbytes = req->nbytes;
+		int idx = 0, err;
+		struct scatterlist *dst, *t;
+		void *saddr;
+
+		if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+			while (nbytes) {
+				t = &ctx->walk.cache[idx];
+				dst = &req->dst[idx];
+
+				dprintk("\n%s: sg_page(t): %p, t->length: %u, "
+					"sg_page(dst): %p, dst->length: %u, "
+					"nbytes: %u.\n",
+					__func__, sg_page(t), t->length,
+					sg_page(dst), dst->length, nbytes);
+
+				if (!t->length) {
+					nbytes -= dst->length;
+					idx++;
+					continue;
+				}
+
+				saddr = kmap_atomic(sg_page(t), KM_IRQ1);
+
+				err = ablkcipher_get(saddr, &t->length, t->offset,
+						dst, nbytes, &nbytes);
+				if (err < 0) {
+					kunmap_atomic(saddr, KM_IRQ1);
+					break;
+				}
+
+				idx += err;
+				kunmap_atomic(saddr, KM_IRQ1);
+			}
+
+			ablkcipher_walk_exit(&ctx->walk);
+		}
+
+		req->base.complete(&req->base, error);
+	}
+}
+
+static void hifn_check_for_completion(struct hifn_device *dev, int error)
+{
+	int i;
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+		struct hifn_desc *d = &dma->resr[i];
+
+		if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) {
+			dev->success++;
+			dev->reset = 0;
+			hifn_process_ready(dev->sa[i], error);
+			dev->sa[i] = NULL;
+		}
+
+		if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER))
+			if (printk_ratelimit())
+				printk("%s: overflow detected [d: %u, o: %u] "
+						"at %d resr: l: %08x, p: %08x.\n",
+					dev->name,
+					!!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)),
+					!!(d->l & __cpu_to_le32(HIFN_D_OVER)),
+					i, d->l, d->p);
+	}
+}
+
+static void hifn_clear_rings(struct hifn_device *dev)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int i, u;
+
+	dprintk("%s: ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, "
+			"k: %d.%d.%d.%d.\n",
+			dev->name,
+			dma->cmdi, dma->srci, dma->dsti, dma->resi,
+			dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+			dma->cmdk, dma->srck, dma->dstk, dma->resk);
+
+	i = dma->resk; u = dma->resu;
+	while (u != 0) {
+		if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+
+		if (i != HIFN_D_RES_RSIZE)
+			u--;
+
+		if (++i == (HIFN_D_RES_RSIZE + 1))
+			i = 0;
+	}
+	dma->resk = i; dma->resu = u;
+
+	i = dma->srck; u = dma->srcu;
+	while (u != 0) {
+		if (i == HIFN_D_SRC_RSIZE)
+			i = 0;
+		if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+		i++, u--;
+	}
+	dma->srck = i; dma->srcu = u;
+
+	i = dma->cmdk; u = dma->cmdu;
+	while (u != 0) {
+		if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+		if (i != HIFN_D_CMD_RSIZE)
+			u--;
+		if (++i == (HIFN_D_CMD_RSIZE + 1))
+			i = 0;
+	}
+	dma->cmdk = i; dma->cmdu = u;
+
+	i = dma->dstk; u = dma->dstu;
+	while (u != 0) {
+		if (i == HIFN_D_DST_RSIZE)
+			i = 0;
+		if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+		i++, u--;
+	}
+	dma->dstk = i; dma->dstu = u;
+
+	dprintk("%s: ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, "
+			"k: %d.%d.%d.%d.\n",
+			dev->name,
+			dma->cmdi, dma->srci, dma->dsti, dma->resi,
+			dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+			dma->cmdk, dma->srck, dma->dstk, dma->resk);
+}
+
+static void hifn_work(struct work_struct *work)
+{
+	struct delayed_work *dw = container_of(work, struct delayed_work, work);
+	struct hifn_device *dev = container_of(dw, struct hifn_device, work);
+	unsigned long flags;
+	int reset = 0;
+	u32 r = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->active == 0) {
+		struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+		if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_CMD_BUSY;
+			r |= HIFN_DMACSR_C_CTRL_DIS;
+		}
+		if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_SRC_BUSY;
+			r |= HIFN_DMACSR_S_CTRL_DIS;
+		}
+		if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_DST_BUSY;
+			r |= HIFN_DMACSR_D_CTRL_DIS;
+		}
+		if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_RES_BUSY;
+			r |= HIFN_DMACSR_R_CTRL_DIS;
+		}
+		if (r)
+			hifn_write_1(dev, HIFN_1_DMA_CSR, r);
+	} else
+		dev->active--;
+
+	if (dev->prev_success == dev->success && dev->started)
+		reset = 1;
+	dev->prev_success = dev->success;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (reset) {
+		dprintk("%s: r: %08x, active: %d, started: %d, "
+				"success: %lu: reset: %d.\n",
+			dev->name, r, dev->active, dev->started,
+			dev->success, reset);
+
+		if (++dev->reset >= 5) {
+			dprintk("%s: really hard reset.\n", dev->name);
+			hifn_reset_dma(dev, 1);
+			hifn_stop_device(dev);
+			hifn_start_device(dev);
+			dev->reset = 0;
+		}
+
+		spin_lock_irqsave(&dev->lock, flags);
+		hifn_check_for_completion(dev, -EBUSY);
+		hifn_clear_rings(dev);
+		dev->started = 0;
+		spin_unlock_irqrestore(&dev->lock, flags);
+	}
+
+	schedule_delayed_work(&dev->work, HZ);
+}
+
+static irqreturn_t hifn_interrupt(int irq, void *data)
+{
+	struct hifn_device *dev = (struct hifn_device *)data;
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	u32 dmacsr, restart;
+
+	dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR);
+
+	dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], "
+			"i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n",
+		dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi,
+		dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+		dma->cmdi, dma->srci, dma->dsti, dma->resi);
+
+	if ((dmacsr & dev->dmareg) == 0)
+		return IRQ_NONE;
+
+	hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg);
+
+	if (dmacsr & HIFN_DMACSR_ENGINE)
+		hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR));
+	if (dmacsr & HIFN_DMACSR_PUBDONE)
+		hifn_write_1(dev, HIFN_1_PUB_STATUS,
+			hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE);
+
+	restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER);
+	if (restart) {
+		u32 puisr = hifn_read_0(dev, HIFN_0_PUISR);
+
+		if (printk_ratelimit())
+			printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
+				dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER),
+				!!(dmacsr & HIFN_DMACSR_D_OVER),
+				puisr, !!(puisr & HIFN_PUISR_DSTOVER));
+		if (!!(puisr & HIFN_PUISR_DSTOVER))
+			hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
+		hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER |
+					HIFN_DMACSR_D_OVER));
+	}
+
+	restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
+			HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
+	if (restart) {
+		if (printk_ratelimit())
+			printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
+				dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT),
+				!!(dmacsr & HIFN_DMACSR_S_ABORT),
+				!!(dmacsr & HIFN_DMACSR_D_ABORT),
+				!!(dmacsr & HIFN_DMACSR_R_ABORT));
+		hifn_reset_dma(dev, 1);
+		hifn_init_dma(dev);
+		hifn_init_registers(dev);
+	}
+
+	if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) {
+		dprintk("%s: wait on command.\n", dev->name);
+		dev->dmareg &= ~(HIFN_DMAIER_C_WAIT);
+		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+	}
+
+	tasklet_schedule(&dev->tasklet);
+	hifn_clear_rings(dev);
+
+	return IRQ_HANDLED;
+}
+
+static void hifn_flush(struct hifn_device *dev)
+{
+	unsigned long flags;
+	struct crypto_async_request *async_req;
+	struct hifn_context *ctx;
+	struct ablkcipher_request *req;
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+		struct hifn_desc *d = &dma->resr[i];
+
+		if (dev->sa[i]) {
+			hifn_process_ready(dev->sa[i],
+				(d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0);
+		}
+	}
+
+	while ((async_req = crypto_dequeue_request(&dev->queue))) {
+		ctx = crypto_tfm_ctx(async_req->tfm);
+		req = container_of(async_req, struct ablkcipher_request, base);
+
+		hifn_process_ready(req, -ENODEV);
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static int hifn_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
+		unsigned int len)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+	struct hifn_device *dev = ctx->dev;
+
+	if (len > HIFN_MAX_CRYPT_KEY_LENGTH) {
+		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -1;
+	}
+
+	if (len == HIFN_DES_KEY_LENGTH) {
+		u32 tmp[DES_EXPKEY_WORDS];
+		int ret = des_ekey(tmp, key);
+		
+		if (unlikely(ret == 0) && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+			tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
+			return -EINVAL;
+		}
+	}
+
+	dev->flags &= ~HIFN_FLAG_OLD_KEY;
+
+	memcpy(ctx->key, key, len);
+	ctx->keysize = len;
+
+	return 0;
+}
+
+static int hifn_handle_req(struct ablkcipher_request *req)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev = ctx->dev;
+	int err = -EAGAIN;
+
+	if (dev->started + DIV_ROUND_UP(req->nbytes, PAGE_SIZE) <= HIFN_QUEUE_LENGTH)
+		err = hifn_setup_session(req);
+
+	if (err == -EAGAIN) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&dev->lock, flags);
+		err = ablkcipher_enqueue_request(&dev->queue, req);
+		spin_unlock_irqrestore(&dev->lock, flags);
+	}
+
+	return err;
+}
+
+static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op,
+		u8 type, u8 mode)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	unsigned ivsize;
+
+	ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req));
+
+	if (req->info && mode != ACRYPTO_MODE_ECB) {
+		if (type == ACRYPTO_TYPE_AES_128)
+			ivsize = HIFN_AES_IV_LENGTH;
+		else if (type == ACRYPTO_TYPE_DES)
+			ivsize = HIFN_DES_KEY_LENGTH;
+		else if (type == ACRYPTO_TYPE_3DES)
+			ivsize = HIFN_3DES_KEY_LENGTH;
+	}
+
+	if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) {
+		if (ctx->keysize == 24)
+			type = ACRYPTO_TYPE_AES_192;
+		else if (ctx->keysize == 32)
+			type = ACRYPTO_TYPE_AES_256;
+	}
+
+	ctx->op = op;
+	ctx->mode = mode;
+	ctx->type = type;
+	ctx->iv = req->info;
+	ctx->ivsize = ivsize;
+
+	/*
+	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
+	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
+	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
+	 */
+
+	return hifn_handle_req(req);
+}
+
+static int hifn_process_queue(struct hifn_device *dev)
+{
+	struct crypto_async_request *async_req;
+	struct hifn_context *ctx;
+	struct ablkcipher_request *req;
+	unsigned long flags;
+	int err = 0;
+
+	while (dev->started < HIFN_QUEUE_LENGTH) {
+		spin_lock_irqsave(&dev->lock, flags);
+		async_req = crypto_dequeue_request(&dev->queue);
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		if (!async_req)
+			break;
+
+		ctx = crypto_tfm_ctx(async_req->tfm);
+		req = container_of(async_req, struct ablkcipher_request, base);
+
+		err = hifn_handle_req(req);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op,
+		u8 type, u8 mode)
+{
+	int err;
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev = ctx->dev;
+
+	err = hifn_setup_crypto_req(req, op, type, mode);
+	if (err)
+		return err;
+
+	if (dev->started < HIFN_QUEUE_LENGTH &&	dev->queue.qlen)
+		err = hifn_process_queue(dev);
+
+	return err;
+}
+
+/*
+ * AES ecryption functions.
+ */
+static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * AES decryption functions.
+ */
+static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * DES ecryption functions.
+ */
+static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * DES decryption functions.
+ */
+static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * 3DES ecryption functions.
+ */
+static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * 3DES decryption functions.
+ */
+static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
+}
+
+struct hifn_alg_template
+{
+	char name[CRYPTO_MAX_ALG_NAME];
+	char drv_name[CRYPTO_MAX_ALG_NAME];
+	unsigned int bsize;
+	struct ablkcipher_alg ablkcipher;
+};
+
+static struct hifn_alg_template hifn_alg_templates[] = {
+	/*
+	 * 3DES ECB, CBC, CFB and OFB modes.
+	 */
+	{
+		.name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_cfb,
+			.decrypt	=	hifn_decrypt_3des_cfb,
+		},
+	},
+	{
+		.name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_ofb,
+			.decrypt	=	hifn_decrypt_3des_ofb,
+		},
+	},
+	{
+		.name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_cbc,
+			.decrypt	=	hifn_decrypt_3des_cbc,
+		},
+	},
+	{
+		.name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_ecb,
+			.decrypt	=	hifn_decrypt_3des_ecb,
+		},
+	},
+
+	/*
+	 * DES ECB, CBC, CFB and OFB modes.
+	 */
+	{
+		.name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_cfb,
+			.decrypt	=	hifn_decrypt_des_cfb,
+		},
+	},
+	{
+		.name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_ofb,
+			.decrypt	=	hifn_decrypt_des_ofb,
+		},
+	},
+	{
+		.name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_cbc,
+			.decrypt	=	hifn_decrypt_des_cbc,
+		},
+	},
+	{
+		.name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_ecb,
+			.decrypt	=	hifn_decrypt_des_ecb,
+		},
+	},
+
+	/*
+	 * AES ECB, CBC, CFB and OFB modes.
+	 */
+	{
+		.name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_ecb,
+			.decrypt	=	hifn_decrypt_aes_ecb,
+		},
+	},
+	{
+		.name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_cbc,
+			.decrypt	=	hifn_decrypt_aes_cbc,
+		},
+	},
+	{
+		.name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_cfb,
+			.decrypt	=	hifn_decrypt_aes_cfb,
+		},
+	},
+	{
+		.name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_ofb,
+			.decrypt	=	hifn_decrypt_aes_ofb,
+		},
+	},
+};
+
+static int hifn_cra_init(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg);
+	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+
+	ctx->dev = ha->dev;
+
+	return 0;
+}
+
+static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
+{
+	struct hifn_crypto_alg *alg;
+	int err;
+
+	alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL);
+	if (!alg)
+		return -ENOMEM;
+
+	snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name);
+	snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name);
+
+	alg->alg.cra_priority = 300;
+	alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+	alg->alg.cra_blocksize = t->bsize;
+	alg->alg.cra_ctxsize = sizeof(struct hifn_context);
+	alg->alg.cra_alignmask = 15;
+	if (t->bsize == 8)
+		alg->alg.cra_alignmask = 3;
+	alg->alg.cra_type = &crypto_ablkcipher_type;
+	alg->alg.cra_module = THIS_MODULE;
+	alg->alg.cra_u.ablkcipher = t->ablkcipher;
+	alg->alg.cra_init = hifn_cra_init;
+
+	alg->dev = dev;
+
+	list_add_tail(&alg->entry, &dev->alg_list);
+
+	err = crypto_register_alg(&alg->alg);
+	if (err) {
+		list_del(&alg->entry);
+		kfree(alg);
+	}
+
+	return err;
+}
+
+static void hifn_unregister_alg(struct hifn_device *dev)
+{
+	struct hifn_crypto_alg *a, *n;
+
+	list_for_each_entry_safe(a, n, &dev->alg_list, entry) {
+		list_del(&a->entry);
+		crypto_unregister_alg(&a->alg);
+		kfree(a);
+	}
+}
+
+static int hifn_register_alg(struct hifn_device *dev)
+{
+	int i, err;
+
+	for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) {
+		err = hifn_alg_alloc(dev, &hifn_alg_templates[i]);
+		if (err)
+			goto err_out_exit;
+	}
+
+	return 0;
+
+err_out_exit:
+	hifn_unregister_alg(dev);
+	return err;
+}
+
+static void hifn_tasklet_callback(unsigned long data)
+{
+	struct hifn_device *dev = (struct hifn_device *)data;
+
+	/*
+	 * This is ok to call this without lock being held,
+	 * althogh it modifies some parameters used in parallel,
+	 * (like dev->success), but they are used in process
+	 * context or update is atomic (like setting dev->sa[i] to NULL).
+	 */
+	hifn_check_for_completion(dev, 0);
+}
+
+static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int err, i;
+	struct hifn_device *dev;
+	char name[8];
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+	pci_set_master(pdev);
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (err)
+		goto err_out_disable_pci_device;
+
+	snprintf(name, sizeof(name), "hifn%d",
+			atomic_inc_return(&hifn_dev_number)-1);
+
+	err = pci_request_regions(pdev, name);
+	if (err)
+		goto err_out_disable_pci_device;
+
+	if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE ||
+	    pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE ||
+	    pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) {
+		dprintk("%s: Broken hardware - I/O regions are too small.\n",
+				pci_name(pdev));
+		err = -ENODEV;
+		goto err_out_free_regions;
+	}
+
+	dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg),
+			GFP_KERNEL);
+	if (!dev) {
+		err = -ENOMEM;
+		goto err_out_free_regions;
+	}
+
+	INIT_LIST_HEAD(&dev->alg_list);
+
+	snprintf(dev->name, sizeof(dev->name), "%s", name);
+	spin_lock_init(&dev->lock);
+
+	for (i=0; i<3; ++i) {
+		unsigned long addr, size;
+
+		addr = pci_resource_start(pdev, i);
+		size = pci_resource_len(pdev, i);
+
+		dev->bar[i] = ioremap_nocache(addr, size);
+		if (!dev->bar[i])
+			goto err_out_unmap_bars;
+	}
+
+	dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER);
+	if (!dev->result_mem) {
+		dprintk("Failed to allocate %d pages for result_mem.\n",
+				HIFN_MAX_RESULT_ORDER);
+		goto err_out_unmap_bars;
+	}
+	memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER));
+
+	dev->dst = pci_map_single(pdev, (void *)dev->result_mem,
+			PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE);
+
+	dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma),
+			&dev->desc_dma);
+	if (!dev->desc_virt) {
+		dprintk("Failed to allocate descriptor rings.\n");
+		goto err_out_free_result_pages;
+	}
+	memset(dev->desc_virt, 0, sizeof(struct hifn_dma));
+
+	dev->pdev = pdev;
+	dev->irq = pdev->irq;
+
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i)
+		dev->sa[i] = NULL;
+
+	pci_set_drvdata(pdev, dev);
+
+	tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
+
+	crypto_init_queue(&dev->queue, 1);
+
+	err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
+	if (err) {
+		dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err);
+		dev->irq = 0;
+		goto err_out_free_desc;
+	}
+
+	err = hifn_start_device(dev);
+	if (err)
+		goto err_out_free_irq;
+
+	err = hifn_test(dev, 1, 0);
+	if (err)
+		goto err_out_stop_device;
+
+	err = hifn_register_rng(dev);
+	if (err)
+		goto err_out_stop_device;
+
+	err = hifn_register_alg(dev);
+	if (err)
+		goto err_out_unregister_rng;
+
+	INIT_DELAYED_WORK(&dev->work, hifn_work);
+	schedule_delayed_work(&dev->work, HZ);
+
+	dprintk("HIFN crypto accelerator card at %s has been "
+			"successfully registered as %s.\n",
+			pci_name(pdev), dev->name);
+
+	return 0;
+
+err_out_unregister_rng:
+	hifn_unregister_rng(dev);
+err_out_stop_device:
+	hifn_reset_dma(dev, 1);
+	hifn_stop_device(dev);
+err_out_free_irq:
+	free_irq(dev->irq, dev->name);
+	tasklet_kill(&dev->tasklet);
+err_out_free_desc:
+	pci_free_consistent(pdev, sizeof(struct hifn_dma),
+			dev->desc_virt, dev->desc_dma);
+
+err_out_free_result_pages:
+	pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
+			PCI_DMA_FROMDEVICE);
+	free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+
+err_out_unmap_bars:
+	for (i=0; i<3; ++i)
+		if (dev->bar[i])
+			iounmap(dev->bar[i]);
+
+err_out_free_regions:
+	pci_release_regions(pdev);
+
+err_out_disable_pci_device:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void hifn_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct hifn_device *dev;
+
+	dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		cancel_delayed_work(&dev->work);
+		flush_scheduled_work();
+
+		hifn_unregister_rng(dev);
+		hifn_unregister_alg(dev);
+		hifn_reset_dma(dev, 1);
+		hifn_stop_device(dev);
+
+		free_irq(dev->irq, dev->name);
+		tasklet_kill(&dev->tasklet);
+
+		hifn_flush(dev);
+
+		pci_free_consistent(pdev, sizeof(struct hifn_dma),
+				dev->desc_virt, dev->desc_dma);
+		pci_unmap_single(pdev, dev->dst,
+				PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
+				PCI_DMA_FROMDEVICE);
+		free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+		for (i=0; i<3; ++i)
+			if (dev->bar[i])
+				iounmap(dev->bar[i]);
+
+		kfree(dev);
+	}
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id hifn_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
+
+static struct pci_driver hifn_pci_driver = {
+	.name     = "hifn795x",
+	.id_table = hifn_pci_tbl,
+	.probe    = hifn_probe,
+	.remove   = __devexit_p(hifn_remove),
+};
+
+static int __devinit hifn_init(void)
+{
+	unsigned int freq;
+	int err;
+
+	if (strncmp(hifn_pll_ref, "ext", 3) &&
+	    strncmp(hifn_pll_ref, "pci", 3)) {
+		printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
+				"must be pci or ext");
+		return -EINVAL;
+	}
+
+	/*
+	 * For the 7955/7956 the reference clock frequency must be in the
+	 * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz,
+	 * but this chip is currently not supported.
+	 */
+	if (hifn_pll_ref[3] != '\0') {
+		freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
+		if (freq < 20 || freq > 100) {
+			printk(KERN_ERR "hifn795x: invalid hifn_pll_ref "
+					"frequency, must be in the range "
+					"of 20-100");
+			return -EINVAL;
+		}
+	}
+
+	err = pci_register_driver(&hifn_pci_driver);
+	if (err < 0) {
+		dprintk("Failed to register PCI driver for %s device.\n",
+				hifn_pci_driver.name);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
+			"has been successfully registered.\n");
+
+	return 0;
+}
+
+static void __devexit hifn_fini(void)
+{
+	pci_unregister_driver(&hifn_pci_driver);
+
+	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
+			"has been successfully unregistered.\n");
+}
+
+module_init(hifn_init);
+module_exit(hifn_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip.");

+ 16 - 8
drivers/crypto/padlock-aes.c

@@ -44,6 +44,7 @@
  */
  */
 
 
 #include <crypto/algapi.h>
 #include <crypto/algapi.h>
+#include <crypto/aes.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/types.h>
@@ -53,9 +54,6 @@
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include "padlock.h"
 #include "padlock.h"
 
 
-#define AES_MIN_KEY_SIZE	16	/* in uint8_t units */
-#define AES_MAX_KEY_SIZE	32	/* ditto */
-#define AES_BLOCK_SIZE		16	/* ditto */
 #define AES_EXTENDED_KEY_SIZE	64	/* in uint32_t units */
 #define AES_EXTENDED_KEY_SIZE	64	/* in uint32_t units */
 #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
 #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
 
 
@@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 /* ====== Encryption/decryption routines ====== */
 /* ====== Encryption/decryption routines ====== */
 
 
 /* These are the real call to PadLock. */
 /* These are the real call to PadLock. */
+static inline void padlock_reset_key(void)
+{
+	asm volatile ("pushfl; popfl");
+}
+
 static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
 static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
 				  void *control_word)
 				  void *control_word)
 {
 {
@@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
 static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
 static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
 			     struct cword *cword)
 			     struct cword *cword)
 {
 {
-	asm volatile ("pushfl; popfl");
-
 	/* padlock_xcrypt requires at least two blocks of data. */
 	/* padlock_xcrypt requires at least two blocks of data. */
 	if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
 	if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
 		       (PAGE_SIZE - 1)))) {
 		       (PAGE_SIZE - 1)))) {
@@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
 		return;
 		return;
 	}
 	}
 
 
-	asm volatile ("pushfl; popfl");		/* enforce key reload. */
 	asm volatile ("test $1, %%cl;"
 	asm volatile ("test $1, %%cl;"
 		      "je 1f;"
 		      "je 1f;"
 		      "lea -1(%%ecx), %%eax;"
 		      "lea -1(%%ecx), %%eax;"
@@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
 static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
 static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
 				     u8 *iv, void *control_word, u32 count)
 				     u8 *iv, void *control_word, u32 count)
 {
 {
-	/* Enforce key reload. */
-	asm volatile ("pushfl; popfl");
 	/* rep xcryptcbc */
 	/* rep xcryptcbc */
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
 		      : "+S" (input), "+D" (output), "+a" (iv)
 		      : "+S" (input), "+D" (output), "+a" (iv)
@@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
 	struct aes_ctx *ctx = aes_ctx(tfm);
 	struct aes_ctx *ctx = aes_ctx(tfm);
+	padlock_reset_key();
 	aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
 	aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
 }
 }
 
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 {
 	struct aes_ctx *ctx = aes_ctx(tfm);
 	struct aes_ctx *ctx = aes_ctx(tfm);
+	padlock_reset_key();
 	aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
 	aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
 }
 }
 
 
@@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err;
 	int err;
 
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
 
 
@@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err;
 	int err;
 
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
 
 
@@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err;
 	int err;
 
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
 
 
@@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	struct blkcipher_walk walk;
 	int err;
 	int err;
 
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 	err = blkcipher_walk_virt(desc, &walk);
 
 

+ 105 - 0
include/crypto/aead.h

@@ -0,0 +1,105 @@
+/*
+ * AEAD: Authenticated Encryption with Associated Data
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CRYPTO_AEAD_H
+#define _CRYPTO_AEAD_H
+
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+/**
+ *	struct aead_givcrypt_request - AEAD request with IV generation
+ *	@seq: Sequence number for IV generation
+ *	@giv: Space for generated IV
+ *	@areq: The AEAD request itself
+ */
+struct aead_givcrypt_request {
+	u64 seq;
+	u8 *giv;
+
+	struct aead_request areq;
+};
+
+static inline struct crypto_aead *aead_givcrypt_reqtfm(
+	struct aead_givcrypt_request *req)
+{
+	return crypto_aead_reqtfm(&req->areq);
+}
+
+static inline int crypto_aead_givencrypt(struct aead_givcrypt_request *req)
+{
+	struct aead_tfm *crt = crypto_aead_crt(aead_givcrypt_reqtfm(req));
+	return crt->givencrypt(req);
+};
+
+static inline int crypto_aead_givdecrypt(struct aead_givcrypt_request *req)
+{
+	struct aead_tfm *crt = crypto_aead_crt(aead_givcrypt_reqtfm(req));
+	return crt->givdecrypt(req);
+};
+
+static inline void aead_givcrypt_set_tfm(struct aead_givcrypt_request *req,
+					 struct crypto_aead *tfm)
+{
+	req->areq.base.tfm = crypto_aead_tfm(tfm);
+}
+
+static inline struct aead_givcrypt_request *aead_givcrypt_alloc(
+	struct crypto_aead *tfm, gfp_t gfp)
+{
+	struct aead_givcrypt_request *req;
+
+	req = kmalloc(sizeof(struct aead_givcrypt_request) +
+		      crypto_aead_reqsize(tfm), gfp);
+
+	if (likely(req))
+		aead_givcrypt_set_tfm(req, tfm);
+
+	return req;
+}
+
+static inline void aead_givcrypt_free(struct aead_givcrypt_request *req)
+{
+	kfree(req);
+}
+
+static inline void aead_givcrypt_set_callback(
+	struct aead_givcrypt_request *req, u32 flags,
+	crypto_completion_t complete, void *data)
+{
+	aead_request_set_callback(&req->areq, flags, complete, data);
+}
+
+static inline void aead_givcrypt_set_crypt(struct aead_givcrypt_request *req,
+					   struct scatterlist *src,
+					   struct scatterlist *dst,
+					   unsigned int nbytes, void *iv)
+{
+	aead_request_set_crypt(&req->areq, src, dst, nbytes, iv);
+}
+
+static inline void aead_givcrypt_set_assoc(struct aead_givcrypt_request *req,
+					   struct scatterlist *assoc,
+					   unsigned int assoclen)
+{
+	aead_request_set_assoc(&req->areq, assoc, assoclen);
+}
+
+static inline void aead_givcrypt_set_giv(struct aead_givcrypt_request *req,
+					 u8 *giv, u64 seq)
+{
+	req->giv = giv;
+	req->seq = seq;
+}
+
+#endif	/* _CRYPTO_AEAD_H */

+ 31 - 0
include/crypto/aes.h

@@ -0,0 +1,31 @@
+/*
+ * Common values for AES algorithms
+ */
+
+#ifndef _CRYPTO_AES_H
+#define _CRYPTO_AES_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define AES_MIN_KEY_SIZE	16
+#define AES_MAX_KEY_SIZE	32
+#define AES_KEYSIZE_128		16
+#define AES_KEYSIZE_192		24
+#define AES_KEYSIZE_256		32
+#define AES_BLOCK_SIZE		16
+
+struct crypto_aes_ctx {
+	u32 key_length;
+	u32 key_enc[60];
+	u32 key_dec[60];
+};
+
+extern u32 crypto_ft_tab[4][256];
+extern u32 crypto_fl_tab[4][256];
+extern u32 crypto_it_tab[4][256];
+extern u32 crypto_il_tab[4][256];
+
+int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		unsigned int key_len);
+#endif

+ 21 - 10
include/crypto/algapi.h

@@ -111,8 +111,15 @@ void crypto_drop_spawn(struct crypto_spawn *spawn);
 struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
 struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
 				    u32 mask);
 				    u32 mask);
 
 
+static inline void crypto_set_spawn(struct crypto_spawn *spawn,
+				    struct crypto_instance *inst)
+{
+	spawn->inst = inst;
+}
+
 struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
 struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
 int crypto_check_attr_type(struct rtattr **tb, u32 type);
 int crypto_check_attr_type(struct rtattr **tb, u32 type);
+const char *crypto_attr_alg_name(struct rtattr *rta);
 struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask);
 struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask);
 int crypto_attr_u32(struct rtattr *rta, u32 *num);
 int crypto_attr_u32(struct rtattr *rta, u32 *num);
 struct crypto_instance *crypto_alloc_instance(const char *name,
 struct crypto_instance *crypto_alloc_instance(const char *name,
@@ -124,6 +131,10 @@ int crypto_enqueue_request(struct crypto_queue *queue,
 struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
 struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
 int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);
 int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);
 
 
+/* These functions require the input/output to be aligned as u32. */
+void crypto_inc(u8 *a, unsigned int size);
+void crypto_xor(u8 *dst, const u8 *src, unsigned int size);
+
 int blkcipher_walk_done(struct blkcipher_desc *desc,
 int blkcipher_walk_done(struct blkcipher_desc *desc,
 			struct blkcipher_walk *walk, int err);
 			struct blkcipher_walk *walk, int err);
 int blkcipher_walk_virt(struct blkcipher_desc *desc,
 int blkcipher_walk_virt(struct blkcipher_desc *desc,
@@ -187,20 +198,11 @@ static inline struct crypto_instance *crypto_aead_alg_instance(
 	return crypto_tfm_alg_instance(&aead->base);
 	return crypto_tfm_alg_instance(&aead->base);
 }
 }
 
 
-static inline struct crypto_ablkcipher *crypto_spawn_ablkcipher(
-	struct crypto_spawn *spawn)
-{
-	u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
-	u32 mask = CRYPTO_ALG_TYPE_MASK;
-
-	return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
-}
-
 static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
 static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
 	struct crypto_spawn *spawn)
 	struct crypto_spawn *spawn)
 {
 {
 	u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
 	u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
-	u32 mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+	u32 mask = CRYPTO_ALG_TYPE_MASK;
 
 
 	return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
 	return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
 }
 }
@@ -303,5 +305,14 @@ static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb,
 	return crypto_attr_alg(tb[1], type, mask);
 	return crypto_attr_alg(tb[1], type, mask);
 }
 }
 
 
+/*
+ * Returns CRYPTO_ALG_ASYNC if type/mask requires the use of sync algorithms.
+ * Otherwise returns zero.
+ */
+static inline int crypto_requires_sync(u32 type, u32 mask)
+{
+	return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC;
+}
+
 #endif	/* _CRYPTO_ALGAPI_H */
 #endif	/* _CRYPTO_ALGAPI_H */
 
 

+ 27 - 0
include/crypto/authenc.h

@@ -0,0 +1,27 @@
+/*
+ * Authenc: Simple AEAD wrapper for IPsec
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ *
+ */
+#ifndef _CRYPTO_AUTHENC_H
+#define _CRYPTO_AUTHENC_H
+
+#include <linux/types.h>
+
+enum {
+	CRYPTO_AUTHENC_KEYA_UNSPEC,
+	CRYPTO_AUTHENC_KEYA_PARAM,
+};
+
+struct crypto_authenc_key_param {
+	__be32 enckeylen;
+};
+
+#endif	/* _CRYPTO_AUTHENC_H */
+

+ 20 - 0
include/crypto/ctr.h

@@ -0,0 +1,20 @@
+/*
+ * CTR: Counter mode
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CRYPTO_CTR_H
+#define _CRYPTO_CTR_H
+
+#define CTR_RFC3686_NONCE_SIZE 4
+#define CTR_RFC3686_IV_SIZE 8
+#define CTR_RFC3686_BLOCK_SIZE 16
+
+#endif  /* _CRYPTO_CTR_H */

+ 19 - 0
include/crypto/des.h

@@ -0,0 +1,19 @@
+/* 
+ * DES & Triple DES EDE Cipher Algorithms.
+ */
+
+#ifndef __CRYPTO_DES_H
+#define __CRYPTO_DES_H
+
+#define DES_KEY_SIZE		8
+#define DES_EXPKEY_WORDS	32
+#define DES_BLOCK_SIZE		8
+
+#define DES3_EDE_KEY_SIZE	(3 * DES_KEY_SIZE)
+#define DES3_EDE_EXPKEY_WORDS	(3 * DES_EXPKEY_WORDS)
+#define DES3_EDE_BLOCK_SIZE	DES_BLOCK_SIZE
+
+
+extern unsigned long des_ekey(u32 *pe, const u8 *k);
+
+#endif /* __CRYPTO_DES_H */

+ 80 - 0
include/crypto/internal/aead.h

@@ -0,0 +1,80 @@
+/*
+ * AEAD: Authenticated Encryption with Associated Data
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CRYPTO_INTERNAL_AEAD_H
+#define _CRYPTO_INTERNAL_AEAD_H
+
+#include <crypto/aead.h>
+#include <crypto/algapi.h>
+#include <linux/types.h>
+
+struct rtattr;
+
+struct crypto_aead_spawn {
+	struct crypto_spawn base;
+};
+
+extern const struct crypto_type crypto_nivaead_type;
+
+static inline void crypto_set_aead_spawn(
+	struct crypto_aead_spawn *spawn, struct crypto_instance *inst)
+{
+	crypto_set_spawn(&spawn->base, inst);
+}
+
+int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
+		     u32 type, u32 mask);
+
+static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn)
+{
+	crypto_drop_spawn(&spawn->base);
+}
+
+static inline struct crypto_alg *crypto_aead_spawn_alg(
+	struct crypto_aead_spawn *spawn)
+{
+	return spawn->base.alg;
+}
+
+static inline struct crypto_aead *crypto_spawn_aead(
+	struct crypto_aead_spawn *spawn)
+{
+	return __crypto_aead_cast(
+		crypto_spawn_tfm(&spawn->base, CRYPTO_ALG_TYPE_AEAD,
+				 CRYPTO_ALG_TYPE_MASK));
+}
+
+struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
+					 struct rtattr **tb, u32 type,
+					 u32 mask);
+void aead_geniv_free(struct crypto_instance *inst);
+int aead_geniv_init(struct crypto_tfm *tfm);
+void aead_geniv_exit(struct crypto_tfm *tfm);
+
+static inline struct crypto_aead *aead_geniv_base(struct crypto_aead *geniv)
+{
+	return crypto_aead_crt(geniv)->base;
+}
+
+static inline void *aead_givcrypt_reqctx(struct aead_givcrypt_request *req)
+{
+	return aead_request_ctx(&req->areq);
+}
+
+static inline void aead_givcrypt_complete(struct aead_givcrypt_request *req,
+					  int err)
+{
+	aead_request_complete(&req->areq, err);
+}
+
+#endif	/* _CRYPTO_INTERNAL_AEAD_H */
+

+ 110 - 0
include/crypto/internal/skcipher.h

@@ -0,0 +1,110 @@
+/*
+ * Symmetric key ciphers.
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CRYPTO_INTERNAL_SKCIPHER_H
+#define _CRYPTO_INTERNAL_SKCIPHER_H
+
+#include <crypto/algapi.h>
+#include <crypto/skcipher.h>
+#include <linux/types.h>
+
+struct rtattr;
+
+struct crypto_skcipher_spawn {
+	struct crypto_spawn base;
+};
+
+extern const struct crypto_type crypto_givcipher_type;
+
+static inline void crypto_set_skcipher_spawn(
+	struct crypto_skcipher_spawn *spawn, struct crypto_instance *inst)
+{
+	crypto_set_spawn(&spawn->base, inst);
+}
+
+int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
+			 u32 type, u32 mask);
+
+static inline void crypto_drop_skcipher(struct crypto_skcipher_spawn *spawn)
+{
+	crypto_drop_spawn(&spawn->base);
+}
+
+static inline struct crypto_alg *crypto_skcipher_spawn_alg(
+	struct crypto_skcipher_spawn *spawn)
+{
+	return spawn->base.alg;
+}
+
+static inline struct crypto_ablkcipher *crypto_spawn_skcipher(
+	struct crypto_skcipher_spawn *spawn)
+{
+	return __crypto_ablkcipher_cast(
+		crypto_spawn_tfm(&spawn->base, crypto_skcipher_type(0),
+				 crypto_skcipher_mask(0)));
+}
+
+int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req);
+int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req);
+const char *crypto_default_geniv(const struct crypto_alg *alg);
+
+struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl,
+					     struct rtattr **tb, u32 type,
+					     u32 mask);
+void skcipher_geniv_free(struct crypto_instance *inst);
+int skcipher_geniv_init(struct crypto_tfm *tfm);
+void skcipher_geniv_exit(struct crypto_tfm *tfm);
+
+static inline struct crypto_ablkcipher *skcipher_geniv_cipher(
+	struct crypto_ablkcipher *geniv)
+{
+	return crypto_ablkcipher_crt(geniv)->base;
+}
+
+static inline int skcipher_enqueue_givcrypt(
+	struct crypto_queue *queue, struct skcipher_givcrypt_request *request)
+{
+	return ablkcipher_enqueue_request(queue, &request->creq);
+}
+
+static inline struct skcipher_givcrypt_request *skcipher_dequeue_givcrypt(
+	struct crypto_queue *queue)
+{
+	return container_of(ablkcipher_dequeue_request(queue),
+			    struct skcipher_givcrypt_request, creq);
+}
+
+static inline void *skcipher_givcrypt_reqctx(
+	struct skcipher_givcrypt_request *req)
+{
+	return ablkcipher_request_ctx(&req->creq);
+}
+
+static inline void ablkcipher_request_complete(struct ablkcipher_request *req,
+					       int err)
+{
+	req->base.complete(&req->base, err);
+}
+
+static inline void skcipher_givcrypt_complete(
+	struct skcipher_givcrypt_request *req, int err)
+{
+	ablkcipher_request_complete(&req->creq, err);
+}
+
+static inline u32 ablkcipher_request_flags(struct ablkcipher_request *req)
+{
+	return req->base.flags;
+}
+
+#endif	/* _CRYPTO_INTERNAL_SKCIPHER_H */
+

+ 42 - 3
crypto/scatterwalk.h → include/crypto/scatterwalk.h

@@ -1,9 +1,10 @@
 /*
 /*
- * Cryptographic API.
+ * Cryptographic scatter and gather helpers.
  *
  *
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com>
  * Copyright (c) 2002 Adam J. Richter <adam@yggdrasil.com>
  * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
  * Copyright (c) 2004 Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -15,14 +16,52 @@
 #ifndef _CRYPTO_SCATTERWALK_H
 #ifndef _CRYPTO_SCATTERWALK_H
 #define _CRYPTO_SCATTERWALK_H
 #define _CRYPTO_SCATTERWALK_H
 
 
+#include <asm/kmap_types.h>
+#include <crypto/algapi.h>
+#include <linux/hardirq.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
+#include <linux/sched.h>
 
 
-#include "internal.h"
+static inline enum km_type crypto_kmap_type(int out)
+{
+	enum km_type type;
+
+	if (in_softirq())
+		type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0;
+	else
+		type = out * (KM_USER1 - KM_USER0) + KM_USER0;
+
+	return type;
+}
+
+static inline void *crypto_kmap(struct page *page, int out)
+{
+	return kmap_atomic(page, crypto_kmap_type(out));
+}
+
+static inline void crypto_kunmap(void *vaddr, int out)
+{
+	kunmap_atomic(vaddr, crypto_kmap_type(out));
+}
+
+static inline void crypto_yield(u32 flags)
+{
+	if (flags & CRYPTO_TFM_REQ_MAY_SLEEP)
+		cond_resched();
+}
+
+static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num,
+					struct scatterlist *sg2)
+{
+	sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
+}
 
 
 static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
 static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
 {
 {
-	return (++sg)->length ? sg : (void *) sg_page(sg);
+	return (++sg)->length ? sg : (void *)sg_page(sg);
 }
 }
 
 
 static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
 static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,

+ 12 - 0
include/crypto/sha.h

@@ -8,6 +8,9 @@
 #define SHA1_DIGEST_SIZE        20
 #define SHA1_DIGEST_SIZE        20
 #define SHA1_BLOCK_SIZE         64
 #define SHA1_BLOCK_SIZE         64
 
 
+#define SHA224_DIGEST_SIZE	28
+#define SHA224_BLOCK_SIZE	64
+
 #define SHA256_DIGEST_SIZE      32
 #define SHA256_DIGEST_SIZE      32
 #define SHA256_BLOCK_SIZE       64
 #define SHA256_BLOCK_SIZE       64
 
 
@@ -23,6 +26,15 @@
 #define SHA1_H3		0x10325476UL
 #define SHA1_H3		0x10325476UL
 #define SHA1_H4		0xc3d2e1f0UL
 #define SHA1_H4		0xc3d2e1f0UL
 
 
+#define SHA224_H0	0xc1059ed8UL
+#define SHA224_H1	0x367cd507UL
+#define SHA224_H2	0x3070dd17UL
+#define SHA224_H3	0xf70e5939UL
+#define SHA224_H4	0xffc00b31UL
+#define SHA224_H5	0x68581511UL
+#define SHA224_H6	0x64f98fa7UL
+#define SHA224_H7	0xbefa4fa4UL
+
 #define SHA256_H0	0x6a09e667UL
 #define SHA256_H0	0x6a09e667UL
 #define SHA256_H1	0xbb67ae85UL
 #define SHA256_H1	0xbb67ae85UL
 #define SHA256_H2	0x3c6ef372UL
 #define SHA256_H2	0x3c6ef372UL

+ 110 - 0
include/crypto/skcipher.h

@@ -0,0 +1,110 @@
+/*
+ * Symmetric key ciphers.
+ * 
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CRYPTO_SKCIPHER_H
+#define _CRYPTO_SKCIPHER_H
+
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+/**
+ *	struct skcipher_givcrypt_request - Crypto request with IV generation
+ *	@seq: Sequence number for IV generation
+ *	@giv: Space for generated IV
+ *	@creq: The crypto request itself
+ */
+struct skcipher_givcrypt_request {
+	u64 seq;
+	u8 *giv;
+
+	struct ablkcipher_request creq;
+};
+
+static inline struct crypto_ablkcipher *skcipher_givcrypt_reqtfm(
+	struct skcipher_givcrypt_request *req)
+{
+	return crypto_ablkcipher_reqtfm(&req->creq);
+}
+
+static inline int crypto_skcipher_givencrypt(
+	struct skcipher_givcrypt_request *req)
+{
+	struct ablkcipher_tfm *crt =
+		crypto_ablkcipher_crt(skcipher_givcrypt_reqtfm(req));
+	return crt->givencrypt(req);
+};
+
+static inline int crypto_skcipher_givdecrypt(
+	struct skcipher_givcrypt_request *req)
+{
+	struct ablkcipher_tfm *crt =
+		crypto_ablkcipher_crt(skcipher_givcrypt_reqtfm(req));
+	return crt->givdecrypt(req);
+};
+
+static inline void skcipher_givcrypt_set_tfm(
+	struct skcipher_givcrypt_request *req, struct crypto_ablkcipher *tfm)
+{
+	req->creq.base.tfm = crypto_ablkcipher_tfm(tfm);
+}
+
+static inline struct skcipher_givcrypt_request *skcipher_givcrypt_cast(
+	struct crypto_async_request *req)
+{
+	return container_of(ablkcipher_request_cast(req),
+			    struct skcipher_givcrypt_request, creq);
+}
+
+static inline struct skcipher_givcrypt_request *skcipher_givcrypt_alloc(
+	struct crypto_ablkcipher *tfm, gfp_t gfp)
+{
+	struct skcipher_givcrypt_request *req;
+
+	req = kmalloc(sizeof(struct skcipher_givcrypt_request) +
+		      crypto_ablkcipher_reqsize(tfm), gfp);
+
+	if (likely(req))
+		skcipher_givcrypt_set_tfm(req, tfm);
+
+	return req;
+}
+
+static inline void skcipher_givcrypt_free(struct skcipher_givcrypt_request *req)
+{
+	kfree(req);
+}
+
+static inline void skcipher_givcrypt_set_callback(
+	struct skcipher_givcrypt_request *req, u32 flags,
+	crypto_completion_t complete, void *data)
+{
+	ablkcipher_request_set_callback(&req->creq, flags, complete, data);
+}
+
+static inline void skcipher_givcrypt_set_crypt(
+	struct skcipher_givcrypt_request *req,
+	struct scatterlist *src, struct scatterlist *dst,
+	unsigned int nbytes, void *iv)
+{
+	ablkcipher_request_set_crypt(&req->creq, src, dst, nbytes, iv);
+}
+
+static inline void skcipher_givcrypt_set_giv(
+	struct skcipher_givcrypt_request *req, u8 *giv, u64 seq)
+{
+	req->giv = giv;
+	req->seq = seq;
+}
+
+#endif	/* _CRYPTO_SKCIPHER_H */
+

+ 68 - 35
include/linux/crypto.h

@@ -33,10 +33,13 @@
 #define CRYPTO_ALG_TYPE_DIGEST		0x00000002
 #define CRYPTO_ALG_TYPE_DIGEST		0x00000002
 #define CRYPTO_ALG_TYPE_HASH		0x00000003
 #define CRYPTO_ALG_TYPE_HASH		0x00000003
 #define CRYPTO_ALG_TYPE_BLKCIPHER	0x00000004
 #define CRYPTO_ALG_TYPE_BLKCIPHER	0x00000004
-#define CRYPTO_ALG_TYPE_COMPRESS	0x00000005
-#define CRYPTO_ALG_TYPE_AEAD		0x00000006
+#define CRYPTO_ALG_TYPE_ABLKCIPHER	0x00000005
+#define CRYPTO_ALG_TYPE_GIVCIPHER	0x00000006
+#define CRYPTO_ALG_TYPE_COMPRESS	0x00000008
+#define CRYPTO_ALG_TYPE_AEAD		0x00000009
 
 
 #define CRYPTO_ALG_TYPE_HASH_MASK	0x0000000e
 #define CRYPTO_ALG_TYPE_HASH_MASK	0x0000000e
+#define CRYPTO_ALG_TYPE_BLKCIPHER_MASK	0x0000000c
 
 
 #define CRYPTO_ALG_LARVAL		0x00000010
 #define CRYPTO_ALG_LARVAL		0x00000010
 #define CRYPTO_ALG_DEAD			0x00000020
 #define CRYPTO_ALG_DEAD			0x00000020
@@ -49,6 +52,12 @@
  */
  */
 #define CRYPTO_ALG_NEED_FALLBACK	0x00000100
 #define CRYPTO_ALG_NEED_FALLBACK	0x00000100
 
 
+/*
+ * This bit is set for symmetric key ciphers that have already been wrapped
+ * with a generic IV generator to prevent them from being wrapped again.
+ */
+#define CRYPTO_ALG_GENIV		0x00000200
+
 /*
 /*
  * Transform masks and values (for crt_flags).
  * Transform masks and values (for crt_flags).
  */
  */
@@ -81,13 +90,11 @@
 #define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN
 #define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN
 #elif defined(ARCH_SLAB_MINALIGN)
 #elif defined(ARCH_SLAB_MINALIGN)
 #define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN
 #define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN
+#else
+#define CRYPTO_MINALIGN __alignof__(unsigned long long)
 #endif
 #endif
 
 
-#ifdef CRYPTO_MINALIGN
 #define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN)))
 #define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN)))
-#else
-#define CRYPTO_MINALIGN_ATTR
-#endif
 
 
 struct scatterlist;
 struct scatterlist;
 struct crypto_ablkcipher;
 struct crypto_ablkcipher;
@@ -97,6 +104,8 @@ struct crypto_blkcipher;
 struct crypto_hash;
 struct crypto_hash;
 struct crypto_tfm;
 struct crypto_tfm;
 struct crypto_type;
 struct crypto_type;
+struct aead_givcrypt_request;
+struct skcipher_givcrypt_request;
 
 
 typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err);
 typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err);
 
 
@@ -176,6 +185,10 @@ struct ablkcipher_alg {
 	              unsigned int keylen);
 	              unsigned int keylen);
 	int (*encrypt)(struct ablkcipher_request *req);
 	int (*encrypt)(struct ablkcipher_request *req);
 	int (*decrypt)(struct ablkcipher_request *req);
 	int (*decrypt)(struct ablkcipher_request *req);
+	int (*givencrypt)(struct skcipher_givcrypt_request *req);
+	int (*givdecrypt)(struct skcipher_givcrypt_request *req);
+
+	const char *geniv;
 
 
 	unsigned int min_keysize;
 	unsigned int min_keysize;
 	unsigned int max_keysize;
 	unsigned int max_keysize;
@@ -185,11 +198,16 @@ struct ablkcipher_alg {
 struct aead_alg {
 struct aead_alg {
 	int (*setkey)(struct crypto_aead *tfm, const u8 *key,
 	int (*setkey)(struct crypto_aead *tfm, const u8 *key,
 	              unsigned int keylen);
 	              unsigned int keylen);
+	int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize);
 	int (*encrypt)(struct aead_request *req);
 	int (*encrypt)(struct aead_request *req);
 	int (*decrypt)(struct aead_request *req);
 	int (*decrypt)(struct aead_request *req);
+	int (*givencrypt)(struct aead_givcrypt_request *req);
+	int (*givdecrypt)(struct aead_givcrypt_request *req);
+
+	const char *geniv;
 
 
 	unsigned int ivsize;
 	unsigned int ivsize;
-	unsigned int authsize;
+	unsigned int maxauthsize;
 };
 };
 
 
 struct blkcipher_alg {
 struct blkcipher_alg {
@@ -202,6 +220,8 @@ struct blkcipher_alg {
 		       struct scatterlist *dst, struct scatterlist *src,
 		       struct scatterlist *dst, struct scatterlist *src,
 		       unsigned int nbytes);
 		       unsigned int nbytes);
 
 
+	const char *geniv;
+
 	unsigned int min_keysize;
 	unsigned int min_keysize;
 	unsigned int max_keysize;
 	unsigned int max_keysize;
 	unsigned int ivsize;
 	unsigned int ivsize;
@@ -317,6 +337,11 @@ struct ablkcipher_tfm {
 	              unsigned int keylen);
 	              unsigned int keylen);
 	int (*encrypt)(struct ablkcipher_request *req);
 	int (*encrypt)(struct ablkcipher_request *req);
 	int (*decrypt)(struct ablkcipher_request *req);
 	int (*decrypt)(struct ablkcipher_request *req);
+	int (*givencrypt)(struct skcipher_givcrypt_request *req);
+	int (*givdecrypt)(struct skcipher_givcrypt_request *req);
+
+	struct crypto_ablkcipher *base;
+
 	unsigned int ivsize;
 	unsigned int ivsize;
 	unsigned int reqsize;
 	unsigned int reqsize;
 };
 };
@@ -326,6 +351,11 @@ struct aead_tfm {
 	              unsigned int keylen);
 	              unsigned int keylen);
 	int (*encrypt)(struct aead_request *req);
 	int (*encrypt)(struct aead_request *req);
 	int (*decrypt)(struct aead_request *req);
 	int (*decrypt)(struct aead_request *req);
+	int (*givencrypt)(struct aead_givcrypt_request *req);
+	int (*givdecrypt)(struct aead_givcrypt_request *req);
+
+	struct crypto_aead *base;
+
 	unsigned int ivsize;
 	unsigned int ivsize;
 	unsigned int authsize;
 	unsigned int authsize;
 	unsigned int reqsize;
 	unsigned int reqsize;
@@ -525,17 +555,23 @@ static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast(
 	return (struct crypto_ablkcipher *)tfm;
 	return (struct crypto_ablkcipher *)tfm;
 }
 }
 
 
-static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher(
-	const char *alg_name, u32 type, u32 mask)
+static inline u32 crypto_skcipher_type(u32 type)
 {
 {
-	type &= ~CRYPTO_ALG_TYPE_MASK;
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-	mask |= CRYPTO_ALG_TYPE_MASK;
+	return type;
+}
 
 
-	return __crypto_ablkcipher_cast(
-		crypto_alloc_base(alg_name, type, mask));
+static inline u32 crypto_skcipher_mask(u32 mask)
+{
+	mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+	mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK;
+	return mask;
 }
 }
 
 
+struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name,
+						  u32 type, u32 mask);
+
 static inline struct crypto_tfm *crypto_ablkcipher_tfm(
 static inline struct crypto_tfm *crypto_ablkcipher_tfm(
 	struct crypto_ablkcipher *tfm)
 	struct crypto_ablkcipher *tfm)
 {
 {
@@ -550,11 +586,8 @@ static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm)
 static inline int crypto_has_ablkcipher(const char *alg_name, u32 type,
 static inline int crypto_has_ablkcipher(const char *alg_name, u32 type,
 					u32 mask)
 					u32 mask)
 {
 {
-	type &= ~CRYPTO_ALG_TYPE_MASK;
-	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-	mask |= CRYPTO_ALG_TYPE_MASK;
-
-	return crypto_has_alg(alg_name, type, mask);
+	return crypto_has_alg(alg_name, crypto_skcipher_type(type),
+			      crypto_skcipher_mask(mask));
 }
 }
 
 
 static inline struct ablkcipher_tfm *crypto_ablkcipher_crt(
 static inline struct ablkcipher_tfm *crypto_ablkcipher_crt(
@@ -601,7 +634,9 @@ static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm,
 static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
 static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
 					   const u8 *key, unsigned int keylen)
 					   const u8 *key, unsigned int keylen)
 {
 {
-	return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen);
+	struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(tfm);
+
+	return crt->setkey(crt->base, key, keylen);
 }
 }
 
 
 static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm(
 static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm(
@@ -633,7 +668,7 @@ static inline unsigned int crypto_ablkcipher_reqsize(
 static inline void ablkcipher_request_set_tfm(
 static inline void ablkcipher_request_set_tfm(
 	struct ablkcipher_request *req, struct crypto_ablkcipher *tfm)
 	struct ablkcipher_request *req, struct crypto_ablkcipher *tfm)
 {
 {
-	req->base.tfm = crypto_ablkcipher_tfm(tfm);
+	req->base.tfm = crypto_ablkcipher_tfm(crypto_ablkcipher_crt(tfm)->base);
 }
 }
 
 
 static inline struct ablkcipher_request *ablkcipher_request_cast(
 static inline struct ablkcipher_request *ablkcipher_request_cast(
@@ -686,15 +721,7 @@ static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm)
 	return (struct crypto_aead *)tfm;
 	return (struct crypto_aead *)tfm;
 }
 }
 
 
-static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name,
-						    u32 type, u32 mask)
-{
-	type &= ~CRYPTO_ALG_TYPE_MASK;
-	type |= CRYPTO_ALG_TYPE_AEAD;
-	mask |= CRYPTO_ALG_TYPE_MASK;
-
-	return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask));
-}
+struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask);
 
 
 static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm)
 static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm)
 {
 {
@@ -749,9 +776,13 @@ static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags)
 static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
 static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
 				     unsigned int keylen)
 				     unsigned int keylen)
 {
 {
-	return crypto_aead_crt(tfm)->setkey(tfm, key, keylen);
+	struct aead_tfm *crt = crypto_aead_crt(tfm);
+
+	return crt->setkey(crt->base, key, keylen);
 }
 }
 
 
+int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize);
+
 static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req)
 static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req)
 {
 {
 	return __crypto_aead_cast(req->base.tfm);
 	return __crypto_aead_cast(req->base.tfm);
@@ -775,7 +806,7 @@ static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)
 static inline void aead_request_set_tfm(struct aead_request *req,
 static inline void aead_request_set_tfm(struct aead_request *req,
 					struct crypto_aead *tfm)
 					struct crypto_aead *tfm)
 {
 {
-	req->base.tfm = crypto_aead_tfm(tfm);
+	req->base.tfm = crypto_aead_tfm(crypto_aead_crt(tfm)->base);
 }
 }
 
 
 static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm,
 static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm,
@@ -841,9 +872,9 @@ static inline struct crypto_blkcipher *crypto_blkcipher_cast(
 static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
 static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
 	const char *alg_name, u32 type, u32 mask)
 	const char *alg_name, u32 type, u32 mask)
 {
 {
-	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	type &= ~CRYPTO_ALG_TYPE_MASK;
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-	mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+	mask |= CRYPTO_ALG_TYPE_MASK;
 
 
 	return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
 	return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
 }
 }
@@ -861,9 +892,9 @@ static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm)
 
 
 static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask)
 static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask)
 {
 {
-	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	type &= ~CRYPTO_ALG_TYPE_MASK;
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-	mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+	mask |= CRYPTO_ALG_TYPE_MASK;
 
 
 	return crypto_has_alg(alg_name, type, mask);
 	return crypto_has_alg(alg_name, type, mask);
 }
 }
@@ -1081,6 +1112,7 @@ static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name,
 						    u32 type, u32 mask)
 						    u32 type, u32 mask)
 {
 {
 	type &= ~CRYPTO_ALG_TYPE_MASK;
 	type &= ~CRYPTO_ALG_TYPE_MASK;
+	mask &= ~CRYPTO_ALG_TYPE_MASK;
 	type |= CRYPTO_ALG_TYPE_HASH;
 	type |= CRYPTO_ALG_TYPE_HASH;
 	mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 	mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 
 
@@ -1100,6 +1132,7 @@ static inline void crypto_free_hash(struct crypto_hash *tfm)
 static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask)
 static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask)
 {
 {
 	type &= ~CRYPTO_ALG_TYPE_MASK;
 	type &= ~CRYPTO_ALG_TYPE_MASK;
+	mask &= ~CRYPTO_ALG_TYPE_MASK;
 	type |= CRYPTO_ALG_TYPE_HASH;
 	type |= CRYPTO_ALG_TYPE_HASH;
 	mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 	mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 
 

+ 1 - 1
include/linux/hw_random.h

@@ -33,7 +33,7 @@ struct hwrng {
 	const char *name;
 	const char *name;
 	int (*init)(struct hwrng *rng);
 	int (*init)(struct hwrng *rng);
 	void (*cleanup)(struct hwrng *rng);
 	void (*cleanup)(struct hwrng *rng);
-	int (*data_present)(struct hwrng *rng);
+	int (*data_present)(struct hwrng *rng, int wait);
 	int (*data_read)(struct hwrng *rng, u32 *data);
 	int (*data_read)(struct hwrng *rng, u32 *data);
 	unsigned long priv;
 	unsigned long priv;
 
 

Some files were not shown because too many files changed in this diff