[PATCH 1/2] stream: Stream cipher wrapper

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Added a "stream" template to support stream ciphers (eSTREAM
candidates in particular) within the CryptoAPI framework.

The current patch differed from my first posting (25 Oct) to the
mailing list in several ways:
1. It now uses cia_setiv() only instead of cia_setiv_crypt() in
include/linux/crypto.h. Reason: (a.) it is closer to the semantics of
eSTREAM's API; (b.) I want to avoid setting cia_encrypt and
cia_decrypt to NULL.
2. It uses a blocksize of 1 for stream (as suggested by Evgeniy)
3. It does not let the underlying cipher handle the full encryption of
the buffer any more. Instead it does it in chunks of the underlying
cipher's "block size", like the other block modes. (Most eSTREAM
software candidates seem to have a native "block size").

The current patch uses setkey(key, keylen) and setiv(iv, ivlen). The
eSTREAM's API actually requires setkey(key, keylen, ivlen) and
setiv(iv). The discrepancy arises because I am simply riding on the
existing "struct cipher_alg". I will look into how this discrepancy
can be resolved (perhaps by creating a separate "struct estream_alg").
Until this discrepancy is resolved, some of the eSTREAM ciphers like
SOSEMANUK may not be usable. Ciphers which have a fixed IV length
(e.g. Salsa20) are usable using the current patch.

Swee Heng
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 1f32071..89286ad 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -204,6 +204,15 @@ config CRYPTO_CTR
 	  CTR: Counter mode
 	  This block cipher algorithm is required for IPSec.
 
+config CRYPTO_STREAM
+	tristate "STREAM: Stream cipher support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_MANAGER
+	help
+	  STREAM: Stream cipher wrapper
+	  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 1f87db2..30994a2 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -33,6 +33,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..b6a3ecc
--- /dev/null
+++ b/crypto/stream.c
@@ -0,0 +1,196 @@
+/*
+ * STR: Stream cipher wrapper
+ *
+ * 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,
+ * use both key and IV to generate an encrypted keystream. The following
+ * code provides a wrapper mechanism to call such stream 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 crypto_stream_ctx {
+	struct crypto_cipher *child;
+};
+
+static int crypto_stream_setkey(struct crypto_tfm *parent, const u8 *key,
+				unsigned int keylen)
+{
+	struct crypto_stream_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 int crypto_stream_crypt_walk(struct blkcipher_walk *walk,
+				    struct crypto_cipher *tfm)
+{
+	void (*setiv)(struct crypto_tfm *, const u8 *, unsigned int) =
+		      crypto_cipher_alg(tfm)->cia_setiv;
+	void (*crypt)(struct crypto_tfm *, u8 *, const u8 *) =
+		      crypto_cipher_alg(tfm)->cia_encrypt;
+	unsigned int ivlen = crypto_cipher_alg(tfm)->cia_ivsize;
+	unsigned int bsize = crypto_cipher_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;
+
+	setiv(crypto_cipher_tfm(tfm), iv, ivlen);
+	while (nbytes >= bsize) {
+		crypt(crypto_cipher_tfm(tfm), dst, src);
+		dst += bsize;
+		src += bsize;
+		nbytes -= bsize;
+	}
+	if (nbytes > 0) {
+		ks = kzalloc(bsize, GFP_KERNEL);
+		memcpy(ks, src, nbytes);
+		crypt(crypto_cipher_tfm(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_cipher *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 crypto_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_stream_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_stream_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_stream_ctx *ctx = crypto_tfm_ctx(tfm);
+	crypto_free_cipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_stream_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_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
+	if (IS_ERR(alg))
+		return ERR_PTR(PTR_ERR(alg));
+
+	inst = crypto_alloc_instance("stream", alg);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	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 = alg->cra_cipher.cia_ivsize;
+	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_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;
+
+out_put_alg:
+	crypto_mod_put(alg);
+	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("Stream cipher wrapper");
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index f3110eb..3890a2e 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -214,6 +214,10 @@ struct cipher_alg {
 	                  unsigned int keylen);
 	void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 	void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+
+	unsigned int cia_ivsize;
+	void (*cia_setiv)(struct crypto_tfm *tfm, const u8 *iv,
+			  unsigned int ivlen);
 };
 
 struct digest_alg {

[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux