Sorry I omitted the patch. Here it is. On Nov 13, 2007 3:59 AM, Tan Swee Heng <thesweeheng@xxxxxxxxx> wrote: > This patch implements a template that wraps around an eSTREAM cipher > algorithm and its ivsize. > > For example, an eSTREAM cipher with the name CIPHERNAME and ivsize > IVSIZE will be instantiated as "stream(CIPHERNAME,IVSIZE)" in > cryptomgr. It uses blkcipher to walk over the memory it > encrypts/decrypts. It has been modified to use the crypto_estream_* > type instead of crypto_cipher_*. >
diff --git a/crypto/Kconfig b/crypto/Kconfig index 4ad25fd..27a802f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -211,6 +211,16 @@ config CRYPTO_CTR CTR: Counter mode This block cipher algorithm is required for IPSec. +config CRYPTO_STREAM + tristate "STREAM: Wrapper for eSTREAM ciphers (EXPERIMENTAL)" + depends on EXPERIMENTAL + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + select CRYPTO_ESTREAM + help + STREAM: Wrapper for eSTREAM ciphers + This wrapper is used by stream ciphers submitted to eSTREAM. + config CRYPTO_CRYPTD tristate "Software async crypto daemon" select CRYPTO_ABLKCIPHER diff --git a/crypto/Makefile b/crypto/Makefile index 14afa34..f95206b 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_XTS) += xts.o obj-$(CONFIG_CRYPTO_CTR) += ctr.o +obj-$(CONFIG_CRYPTO_STREAM) += stream.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des_generic.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o diff --git a/crypto/stream.c b/crypto/stream.c new file mode 100644 index 0000000..0c2ffc7 --- /dev/null +++ b/crypto/stream.c @@ -0,0 +1,241 @@ +/* + * STREAM: Wrapper for eSTREAM ciphers + * + * Copyright (c) 2007 Tan Swee Heng <thesweeheng@xxxxxxxxx> + * + * Derived from + * - cbc.c: Copyright (c) 2006 Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> + * - ctr.c: Copyright (c) IBM Corp. 2007 Joy Latten <latten@xxxxxxxxxx> + * + * Stream ciphers submitted to eSTREAM, the ECRYPT Stream Cipher Project, + * requires both key size and IV size in the key setup. This is different + * from standard block ciphers. This wrapper provides the necessary glue + * tp work with such eSTREAM ciphers. + * + * 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/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> + +struct stream_instance_ctx { + struct crypto_spawn alg; + unsigned int ivsize; +}; + +struct crypto_stream_ctx { + struct crypto_estream *child; +}; + +static int crypto_stream_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keysize) +{ + struct crypto_stream_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_estream *child = ctx->child; + struct stream_instance_ctx *ictx = + crypto_instance_ctx(crypto_tfm_alg_instance(parent)); + int err; + + crypto_estream_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_estream_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_estream_setkey(child, key, keysize, ictx->ivsize); + crypto_tfm_set_flags(parent, crypto_estream_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_stream_crypt_walk(struct blkcipher_walk *walk, + struct crypto_estream *tfm) +{ + unsigned int bsize = crypto_estream_blocksize(tfm); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + u8 *ks; + + crypto_estream_setiv(tfm, iv); + while (nbytes >= bsize) { + crypto_estream_encrypt_block(tfm, dst, src); + dst += bsize; + src += bsize; + nbytes -= bsize; + } + if (nbytes > 0) { + ks = kzalloc(bsize, GFP_KERNEL); + memcpy(ks, src, nbytes); + crypto_estream_encrypt_block(tfm, ks, ks); + memcpy(dst, ks, nbytes); + kfree(ks); + } + + return 0; +} + +static int crypto_stream_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_stream_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_estream *child = ctx->child; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while (walk.nbytes) { + nbytes = crypto_stream_crypt_walk(&walk, child); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + + +static int crypto_stream_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct stream_instance_ctx *ictx = crypto_instance_ctx(inst); + struct crypto_stream_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_estream *estream; + + estream = crypto_spawn_estream(&ictx->alg); + if (IS_ERR(estream)) + return PTR_ERR(estream); + + ctx->child = estream; + return 0; +} + +static void crypto_stream_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_stream_ctx *ctx = crypto_tfm_ctx(tfm); + crypto_free_estream(ctx->child); +} + +static struct crypto_instance *crypto_stream_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + struct stream_instance_ctx *ictx; + unsigned int ivsize; + 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_ESTREAM, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(alg)) + return ERR_PTR(PTR_ERR(alg)); + + err = crypto_attr_u32(tb[2], &ivsize); + if (err) + goto out_put_alg; + + err = -EINVAL; + if ((ivsize < alg->cra_estream.min_ivsize) || + (ivsize > alg->cra_estream.max_ivsize)) + goto out_put_alg; + + inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); + err = -ENOMEM; + if (!inst) + goto out_put_alg; + + err = - ENAMETOOLONG; + if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, + "stream(%s,%u)", alg->cra_name, + ivsize) >= CRYPTO_MAX_ALG_NAME) { + goto err_free_inst; + } + + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "stream(%s,%u)", alg->cra_driver_name, + ivsize) >= CRYPTO_MAX_ALG_NAME) { + goto err_free_inst; + } + + ictx = crypto_instance_ctx(inst); + ictx->ivsize = ivsize; + + err = crypto_init_spawn(&ictx->alg, alg, inst, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + if (err) + goto err_free_inst; + + err = 0; + 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 = ivsize; + inst->alg.cra_blkcipher.min_keysize = alg->cra_estream.min_keysize; + inst->alg.cra_blkcipher.max_keysize = alg->cra_estream.max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct crypto_stream_ctx); + + inst->alg.cra_init = crypto_stream_init_tfm; + inst->alg.cra_exit = crypto_stream_exit_tfm; + + inst->alg.cra_blkcipher.setkey = crypto_stream_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_stream_crypt; + inst->alg.cra_blkcipher.decrypt = crypto_stream_crypt; + +err_free_inst: + if (err) + kfree(inst); + +out_put_alg: + crypto_mod_put(alg); + + if(err) + inst = ERR_PTR(err); + + return inst; +} + +static void crypto_stream_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_stream_tmpl = { + .name = "stream", + .alloc = crypto_stream_alloc, + .free = crypto_stream_free, + .module = THIS_MODULE, +}; + +static int __init crypto_stream_module_init(void) +{ + return crypto_register_template(&crypto_stream_tmpl); +} + +static void __exit crypto_stream_module_exit(void) +{ + crypto_unregister_template(&crypto_stream_tmpl); +} + +module_init(crypto_stream_module_init); +module_exit(crypto_stream_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Wrapper for eSTREAM ciphers");