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 <[EMAIL PROTECTED]>
+ *
+ * Code derived from:
+ * cipher.c: Copyright (c) 2002 James Morris <[EMAIL PROTECTED]>
+ * Copyright (c) 2005 Herbert Xu <[EMAIL PROTECTED]>
+ *
+ * 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;