This patch introduces a new crypto_type (and the associated *_alg and *_tfm) to support eSTREAM ciphers. It is created to provide better support for the setiv() operation required by eSTREAM ciphers.
diff --git a/crypto/Kconfig b/crypto/Kconfig index 1f32071..4ad25fd 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -40,6 +40,13 @@ config CRYPTO_HASH tristate select CRYPTO_ALGAPI +config CRYPTO_ESTREAM + tristate "eSTREAM ciphers" + depends on EXPERIMENTAL + select CRYPTO_ALGAPI + help + This is a crypto_type to support eSTREAM ciphers. + config CRYPTO_MANAGER tristate "Cryptographic algorithm manager" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index 1f87db2..14afa34 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o crypto_hash-objs := hash.o obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o +obj-$(CONFIG_CRYPTO_ESTREAM) += estream.o obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o obj-$(CONFIG_CRYPTO_HMAC) += hmac.o diff --git a/crypto/estream.c b/crypto/estream.c new file mode 100644 index 0000000..7ad70ff --- /dev/null +++ b/crypto/estream.c @@ -0,0 +1,165 @@ +/* + * Cryptographic API. + * + * eSTREAM cipher operations. + * + * Copyright (c) 2007 Tan Swee Heng <thesweeheng@xxxxxxxxx> + * + * Code derived from: + * cipher.c: Copyright (c) 2002 James Morris <jmorris@xxxxxxxxxxxxxxxx> + * Copyright (c) 2005 Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> + * + * 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/kernel.h> +#include <linux/crypto.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/seq_file.h> +#include "internal.h" + +static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize, unsigned int ivsize) +{ + struct estream_alg *esa = &tfm->__crt_alg->cra_estream; + unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); + int ret; + u8 *buffer, *alignbuffer; + unsigned long absize; + + absize = keysize + alignmask; + buffer = kmalloc(absize, GFP_ATOMIC); + if (!buffer) + return -ENOMEM; + + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keysize); + ret = esa->setkey(tfm, alignbuffer, keysize, ivsize); + memset(alignbuffer, 0, keysize); + kfree(buffer); + return ret; + +} + +static int setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize, unsigned int ivsize) +{ + struct estream_alg *esa = &tfm->__crt_alg->cra_estream; + unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); + + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + if (ivsize < esa->min_ivsize || ivsize > esa->max_ivsize) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_IV_LEN; + return -EINVAL; + } + tfm->crt_estream.ivsize = ivsize; + + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + if (keysize < esa->min_keysize || keysize > esa->max_keysize) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + if ((unsigned long)key & alignmask) + return setkey_unaligned(tfm, key, keysize, ivsize); + + return esa->setkey(tfm, key, keysize, ivsize); +} + +static int setiv_unaligned(struct crypto_tfm *tfm, const u8 *iv) +{ + struct estream_alg *esa = &tfm->__crt_alg->cra_estream; + unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); + u8 *buffer, *alignbuffer; + unsigned long absize; + unsigned int ivsize; + int ret; + + ivsize = tfm->crt_estream.ivsize; + absize = ivsize + alignmask; + buffer = kmalloc(absize, GFP_ATOMIC); + if (!buffer) + return -ENOMEM; + + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, iv, ivsize); + ret = esa->setiv(tfm, alignbuffer); + kfree(buffer); + return ret; +} + +static int setiv(struct crypto_tfm *tfm, const u8 *iv) +{ + struct estream_alg *esa = &tfm->__crt_alg->cra_estream; + unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); + + if ((unsigned long)iv & alignmask) + return setiv_unaligned(tfm, iv); + return esa->setiv(tfm, iv); +} + +static void encrypt_block_unaligned(struct crypto_tfm *tfm, u8 *dst, + const u8 *src) +{ + unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); + struct estream_alg *esa = &tfm->__crt_alg->cra_estream; + unsigned int size = crypto_tfm_alg_blocksize(tfm); + u8 buffer[size + alignmask]; + u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + + if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { + memcpy(tmp, src, size); + esa->encrypt_block(tfm, tmp, tmp); + memcpy(dst, tmp, size); + return; + } + esa->encrypt_block(tfm, dst, src); +} + +static unsigned int crypto_estream_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) +{ + return alg->cra_ctxsize; +} + +static int crypto_init_estream_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + struct estream_tfm *crt = &tfm->crt_estream; + struct estream_alg *esa = &tfm->__crt_alg->cra_estream; + + crt->ivsize = 0; + crt->setkey = setkey; + crt->setiv = setiv; + crt->encrypt_block = crypto_tfm_alg_alignmask(tfm) ? + encrypt_block_unaligned : esa->encrypt_block; + + return 0; +} + +static void crypto_estream_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_estream_show(struct seq_file *m, struct crypto_alg *alg) +{ + seq_printf(m, "type : estream\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min_keysize : %u\n", alg->cra_estream.min_keysize); + seq_printf(m, "max_keysize : %u\n", alg->cra_estream.max_keysize); + seq_printf(m, "min_ivsize : %u\n", alg->cra_estream.min_ivsize); + seq_printf(m, "max_ivsize : %u\n", alg->cra_estream.max_ivsize); +} + +const struct crypto_type crypto_estream_type = { + .ctxsize = crypto_estream_ctxsize, + .init = crypto_init_estream_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_estream_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_estream_type); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("eSTREAM ciphers"); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index b9b05d3..d462815 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -98,6 +98,7 @@ extern const struct crypto_type crypto_ablkcipher_type; extern const struct crypto_type crypto_aead_type; extern const struct crypto_type crypto_blkcipher_type; extern const struct crypto_type crypto_hash_type; +extern const struct crypto_type crypto_estream_type; void crypto_mod_put(struct crypto_alg *alg); @@ -224,6 +225,15 @@ static inline struct crypto_cipher *crypto_spawn_cipher( return __crypto_cipher_cast(crypto_spawn_tfm(spawn, type, mask)); } +static inline struct crypto_estream *crypto_spawn_estream( + struct crypto_spawn *spawn) +{ + u32 type = CRYPTO_ALG_TYPE_ESTREAM; + u32 mask = CRYPTO_ALG_TYPE_MASK; + + return __crypto_estream_cast(crypto_spawn_tfm(spawn, type, mask)); +} + static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm) { return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher; diff --git a/include/linux/crypto.h b/include/linux/crypto.h index f3110eb..c5b1f64 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -35,6 +35,7 @@ #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 #define CRYPTO_ALG_TYPE_COMPRESS 0x00000005 #define CRYPTO_ALG_TYPE_AEAD 0x00000006 +#define CRYPTO_ALG_TYPE_ESTREAM 0x00000007 #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e @@ -63,6 +64,7 @@ #define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 #define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 #define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 +#define CRYPTO_TFM_RES_BAD_IV_LEN 0x02000000 /* * Miscellaneous stuff. @@ -216,6 +218,17 @@ struct cipher_alg { void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); }; +struct estream_alg { + unsigned int min_keysize; + unsigned int max_keysize; + unsigned int min_ivsize; + unsigned int max_ivsize; + int (*setkey)(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize, unsigned int ivsize); + int (*setiv)(struct crypto_tfm *tfm, const u8 *iv); + void (*encrypt_block)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); +}; + struct digest_alg { unsigned int dia_digestsize; void (*dia_init)(struct crypto_tfm *tfm); @@ -250,6 +263,7 @@ struct compress_alg { #define cra_aead cra_u.aead #define cra_blkcipher cra_u.blkcipher #define cra_cipher cra_u.cipher +#define cra_estream cra_u.estream #define cra_digest cra_u.digest #define cra_hash cra_u.hash #define cra_compress cra_u.compress @@ -276,6 +290,7 @@ struct crypto_alg { struct aead_alg aead; struct blkcipher_alg blkcipher; struct cipher_alg cipher; + struct estream_alg estream; struct digest_alg digest; struct hash_alg hash; struct compress_alg compress; @@ -348,6 +363,14 @@ struct cipher_tfm { void (*cit_decrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); }; +struct estream_tfm { + unsigned int ivsize; + int (*setkey)(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize, unsigned int ivsize); + int (*setiv)(struct crypto_tfm *tfm, const u8 *iv); + void (*encrypt_block)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); +}; + struct hash_tfm { int (*init)(struct hash_desc *desc); int (*update)(struct hash_desc *desc, @@ -373,6 +396,7 @@ struct compress_tfm { #define crt_aead crt_u.aead #define crt_blkcipher crt_u.blkcipher #define crt_cipher crt_u.cipher +#define crt_estream crt_u.estream #define crt_hash crt_u.hash #define crt_compress crt_u.compress @@ -385,6 +409,7 @@ struct crypto_tfm { struct aead_tfm aead; struct blkcipher_tfm blkcipher; struct cipher_tfm cipher; + struct estream_tfm estream; struct hash_tfm hash; struct compress_tfm compress; } crt_u; @@ -410,6 +435,10 @@ struct crypto_cipher { struct crypto_tfm base; }; +struct crypto_estream { + struct crypto_tfm base; +}; + struct crypto_comp { struct crypto_tfm base; }; @@ -1065,6 +1094,81 @@ static inline void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, dst, src); } +static inline struct crypto_estream *__crypto_estream_cast( + struct crypto_tfm *tfm) +{ + return (struct crypto_estream *)tfm; +} + +static inline struct crypto_tfm *crypto_estream_tfm(struct crypto_estream *tfm) +{ + return &tfm->base; +} + +static inline void crypto_free_estream(struct crypto_estream *tfm) +{ + crypto_free_tfm(crypto_estream_tfm(tfm)); +} + +static inline struct estream_tfm *crypto_estream_crt(struct crypto_estream *tfm) +{ + return &crypto_estream_tfm(tfm)->crt_estream; +} + +static inline struct estream_alg *crypto_estream_alg(struct crypto_estream *tfm) +{ + return &crypto_estream_tfm(tfm)->__crt_alg->cra_estream; +} + +static inline unsigned int crypto_estream_ivsize(struct crypto_estream *tfm) +{ + return crypto_estream_crt(tfm)->ivsize; +} + +static inline unsigned int crypto_estream_blocksize(struct crypto_estream *tfm) +{ + return crypto_tfm_alg_blocksize(crypto_estream_tfm(tfm)); +} + +static inline u32 crypto_estream_get_flags(struct crypto_estream *tfm) +{ + return crypto_tfm_get_flags(crypto_estream_tfm(tfm)); +} + +static inline void crypto_estream_set_flags(struct crypto_estream *tfm, + u32 flags) +{ + crypto_tfm_set_flags(crypto_estream_tfm(tfm), flags); +} + +static inline void crypto_estream_clear_flags(struct crypto_estream *tfm, + u32 flags) +{ + crypto_tfm_clear_flags(crypto_estream_tfm(tfm), flags); +} + +static inline int crypto_estream_setkey(struct crypto_estream *tfm, + const u8 *key, + unsigned int keysize, + unsigned int ivsize) +{ + return crypto_estream_crt(tfm)->setkey(crypto_estream_tfm(tfm), + key, keysize, ivsize); +} + +static inline void crypto_estream_setiv(struct crypto_estream *tfm, + const u8 *iv) +{ + crypto_estream_crt(tfm)->setiv(crypto_estream_tfm(tfm), iv); +} + +static inline void crypto_estream_encrypt_block(struct crypto_estream *tfm, + u8 *dst, const u8 *src) +{ + crypto_estream_crt(tfm)->encrypt_block(crypto_estream_tfm(tfm), + dst, src); +} + static inline struct crypto_hash *__crypto_hash_cast(struct crypto_tfm *tfm) { return (struct crypto_hash *)tfm;