All of lore.kernel.org
 help / color / mirror / Atom feed
From: rsnel@cube.dyndns.org
To: herbert@gondor.apana.org.au
Cc: linux-crypto@vger.kernel.org, Rik Snel <rsnel@cube.dyndns.org>
Subject: [PATCHv2 5/6] LRW, Liskov Rivest Wagner, a tweakable narrow block cipher mode
Date: Sat, 02 Sep 2006 03:00:26 +0200	[thread overview]
Message-ID: <115715883237-git-send-email-rsnel@cube.dyndns.org> (raw)
In-Reply-To: <20060901103707.GA17110@gondor.apana.org.au>

From: Rik Snel <rsnel@cube.dyndns.org>

Main module, this implements the Liskov Rivest Wagner block cipher mode
in the new blockcipher API. The implementation is based on ecb.c.

The LRW-32-AES specification I used can be found at:
http://grouper.ieee.org/groups/1619/email/pdf00017.pdf

It implements the optimization specified as optional in the
specification, and in addition it uses optimized multiplication
routines from gf128mul.c.

Since gf128mul.[ch] is not tested on bigendian, this cipher mode
may currently fail badly on bigendian machines.

Signed-off-by: Rik Snel <rsnel@cube.dyndns.org>
---

Note: I rerolled the loop because it turned out that I had unrolled it
wrong. (I noticed it after I added the long testvector; a cypherblock
was split in two by a page boundary and the reconstructed block was
discarded because of an error in the unrolling).

 crypto/Kconfig  |   13 ++
 crypto/Makefile |    1 
 crypto/lrw.c    |  291 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 305 insertions(+), 0 deletions(-)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 6b23c20..dfdfe08 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -156,6 +156,19 @@ config CRYPTO_CBC
 	  CBC: Cipher Block Chaining mode
 	  This block cipher algorithm is required for IPSec.
 
+config CRYPTO_LRW
+	tristate "LRW support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_GF128MUL
+	default n
+	help
+	  LRW: Liskov Rivest Wagner, a tweakable, non malleable, non movable
+	  narrow block cipher mode. Use it with cipher specification string
+	  aes-lrw-benbi, the key must be 256, 320 or 384. The first 128, 192
+	  or 256 bits in the key are used for AES and the rest is used to tie
+	  each cipher block to its logical position.
+
 config CRYPTO_DES
 	tristate "DES and Triple DES EDE cipher algorithms"
 	select CRYPTO_ALGAPI
diff --git a/crypto/Makefile b/crypto/Makefile
index bf0406b..e2e57be 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
 obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
 obj-$(CONFIG_CRYPTO_ECB) += ecb.o
 obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_DES) += des.o
 obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
diff --git a/crypto/lrw.c b/crypto/lrw.c
new file mode 100644
index 0000000..a037379
--- /dev/null
+++ b/crypto/lrw.c
@@ -0,0 +1,291 @@
+/* LRW: as defined by Cyril Guyot in
+ *	http://grouper.ieee.org/groups/1619/email/pdf00017.pdf
+ *
+ * Copyright (c) 2006 Rik Snel <rsnel@cube.dyndns.org>
+ *
+ * Based om ecb.c
+ * Copyright (c) 2006 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.
+ */
+/* This implementation is checked against the test vectors in the above
+ * document and by a test vector provided by Ken Buchanan at
+ * http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html
+ *
+ * The test vectors are included in the testing module tcrypt.[ch] */
+#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>
+
+#include "b128ops.h"
+#include "gf128mul.h"
+
+struct priv {
+	struct crypto_cipher *child;
+	/* optimizes multiplying a random (non incrementing, as at the
+	 * start of a new sector) value with key2, we could also have
+	 * used 4k optimization tables or no optimization at all. In the
+	 * latter case we would have to store key2 here */
+	struct gf128mul_64k table;
+	/* stores:
+	 *  key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 },
+	 *  key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 }
+	 *  key2*{ 0,0,...1,1,1,1,1 }, etc
+	 * needed for optimized multiplication of incrementing values
+	 * with key2 */
+	u64 mulinc[128][GF128MUL_BYTES >> 3];
+};
+
+static inline void setbit128(void *b, int bit)
+{
+	int index = 15 - bit/8;
+	((u8 *)b)[index] |= 1<<(bit%8);
+}
+
+static int setkey(struct crypto_tfm *parent, const u8 *key,
+			     unsigned int keylen)
+{
+	struct priv *ctx = crypto_tfm_ctx(parent);
+	struct crypto_cipher *child = ctx->child;
+	int err, i;
+	u64 tmp[2] = { 0, }, scratch[2];
+	int bsize = crypto_cipher_blocksize(child);
+
+	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+				       CRYPTO_TFM_REQ_MASK);
+	if ((err = crypto_cipher_setkey(child, key, keylen - bsize)))
+		return err;
+	crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+				     CRYPTO_TFM_RES_MASK);
+
+
+	/* initialize multiplication table for Key2 */
+	gf128mul_init_64k_bbe(&ctx->table, (u64 *)(key + keylen - bsize));
+
+	/* initialize optimization table */
+	for (i = 0; i < 128; i++) {
+		setbit128(tmp, i);
+		b128ops_mov(ctx->mulinc[i], tmp);
+		gf128mul_64k_bbe(ctx->mulinc[i], &ctx->table, scratch);
+	}
+
+	return 0;
+}
+
+struct sinfo {
+	u64 b1[2], b2[2];
+	struct crypto_tfm *tfm;
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
+};
+
+static inline void inc(u64 *iv)
+{
+	if (!(iv[1] = cpu_to_be64(be64_to_cpu(iv[1]) + 1)))
+		iv[0] = cpu_to_be64(be64_to_cpu(iv[0]) + 1);
+}
+
+static inline void round(struct sinfo *s, u8 *dst, const u8 *src)
+{
+	b128ops_xor(s->b2, src);		/* PP <- T xor P */
+	s->fn(s->tfm, dst, (u8 *)s->b2);	/* CC <- E(Key2,PP) */
+	b128ops_xor(dst, s->b1);		/* C <- T xor CC */
+}
+
+/* this returns the number of consequative 1 bits
+ * starting from the right in i */
+static inline int get_index8(u8 i)
+{
+	int j = 1;
+
+	if (i&1) {
+		while ((i >>= 1)&1) j++;
+		return j;
+	}
+
+	return 0;
+}
+
+/* this returns the number of consequative 1 bits starting
+ * from the right, get_index128(00 00 00 00 00 00 ... 00 00 10 FB) = 2 */
+static inline int get_index128(u8 *block)
+{
+	int inc, ret = 0, len = 16;
+	while ((inc = get_index8(block[--len])) == 8) ret += 8;
+	return ret + inc;
+}
+
+static int crypt(struct blkcipher_desc *d,
+			    struct scatterlist *dst,
+			    struct scatterlist *src,
+			    unsigned int nbytes, struct priv *ctx,
+			    void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
+{
+	struct blkcipher_walk w;
+	int err, old_t_known = 0;
+	unsigned int avail;
+	const int bs = crypto_cipher_blocksize(ctx->child);
+	struct sinfo s = {
+		.tfm = crypto_cipher_tfm(ctx->child),
+		.fn = fn
+	};
+
+	blkcipher_walk_init(&w, dst, src, nbytes);
+
+	err = blkcipher_walk_virt(d, &w);
+
+	while ((avail = w.nbytes)) {
+		u8 *wsrc = w.src.virt.addr;
+		u8 *wdst = w.dst.virt.addr;
+		do {
+			if (old_t_known) {
+				/* old T is available in s.b1; new one
+			 	 * must be made available in b1 and b2 */
+
+				/* T <- I*Key2, using the optimization
+				 * discussed in the specification */
+				b128ops_xor(s.b1, ctx->mulinc[
+						get_index128(w.iv)]);
+				inc((u64*)w.iv);
+				b128ops_mov(s.b2, s.b1);
+			} else {
+				/* calculate first value of T */
+				b128ops_mov(s.b1, w.iv);
+				/* T <- I*Key2 */
+				gf128mul_64k_bbe(s.b1, &ctx->table, s.b2);
+				old_t_known = 1;
+			}
+
+			round(&s, wdst, wsrc);
+
+			wsrc += bs;
+			wdst += bs;
+		} while ((avail -= bs) >= bs);
+
+		err = blkcipher_walk_done(d, &w, avail);
+	}
+
+	return err;
+}
+
+static int encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		struct scatterlist *src, unsigned int nbytes)
+{
+	struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
+	return crypt(desc, dst, src, nbytes, ctx,
+			crypto_cipher_alg(ctx->child)->cia_encrypt);
+}
+
+static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+		struct scatterlist *src, unsigned int nbytes)
+{
+	struct priv *ctx = crypto_blkcipher_ctx(desc->tfm);
+	return crypt(desc, dst, src, nbytes, ctx,
+			crypto_cipher_alg(ctx->child)->cia_decrypt);
+}
+
+static int init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+	struct priv *ctx = crypto_tfm_ctx(tfm);
+	u32 *flags = &tfm->crt_flags;
+
+	tfm = crypto_spawn_tfm(spawn);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	if (crypto_tfm_alg_blocksize(tfm) != 16) {
+		*flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
+		return -EINVAL;
+	}
+
+	ctx->child = crypto_cipher_cast(tfm);
+	return 0;
+}
+
+static void exit_tfm(struct crypto_tfm *tfm)
+{
+	struct priv *ctx = crypto_tfm_ctx(tfm);
+	crypto_free_cipher(ctx->child);
+}
+
+static struct crypto_instance *alloc(void *param, unsigned int len)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+
+	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	if (IS_ERR(alg))
+		return ERR_PTR(PTR_ERR(alg));
+
+	inst = crypto_alloc_instance("lrw", 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 = alg->cra_blocksize;
+
+	if (alg->cra_alignmask < 7) inst->alg.cra_alignmask = 7;
+	else inst->alg.cra_alignmask = alg->cra_alignmask;
+	inst->alg.cra_type = &crypto_blkcipher_type;
+
+	if (!(alg->cra_blocksize % 4))
+		inst->alg.cra_alignmask |= 3;
+	inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+	inst->alg.cra_blkcipher.min_keysize =
+		alg->cra_cipher.cia_min_keysize + alg->cra_blocksize;
+	inst->alg.cra_blkcipher.max_keysize =
+		alg->cra_cipher.cia_max_keysize + alg->cra_blocksize;
+
+	inst->alg.cra_ctxsize = sizeof(struct priv);
+
+	inst->alg.cra_init = init_tfm;
+	inst->alg.cra_exit = exit_tfm;
+
+	inst->alg.cra_blkcipher.setkey = setkey;
+	inst->alg.cra_blkcipher.encrypt = encrypt;
+	inst->alg.cra_blkcipher.decrypt = decrypt;
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return inst;
+}
+
+static void free(struct crypto_instance *inst)
+{
+	crypto_drop_spawn(crypto_instance_ctx(inst));
+	kfree(inst);
+}
+
+static struct crypto_template crypto_tmpl = {
+	.name = "lrw",
+	.alloc = alloc,
+	.free = free,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_module_init(void)
+{
+	return crypto_register_template(&crypto_tmpl);
+}
+
+static void __exit crypto_module_exit(void)
+{
+	crypto_unregister_template(&crypto_tmpl);
+}
+
+module_init(crypto_module_init);
+module_exit(crypto_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LRW block cipher mode");
-- 
1.4.1.1


-- 
VGER BF report: U 0.5

  parent reply	other threads:[~2006-09-02  1:00 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-31 12:39 LRW implementation, please comment Rik Snel
2006-08-31 12:39 ` [PATCH 1/6] crypto: trivial comment improvements Rik Snel
2006-08-31 12:39 ` [PATCH 2/6] crypto: benbi IV, big endian narrow block count for LRW-32-AES Rik Snel
2006-08-31 12:39 ` [PATCH 3/6] crypto: some common 128-bit block operations, nicely centralized Rik Snel
2006-08-31 12:39 ` [PATCH 4/6] crypto: table driven multiplications in GF(2^128), needed by LRW (and in the future ABL) Rik Snel
2006-08-31 12:39 ` [PATCH 5/6] crypto: LRW, Liskov Rivest Wagner, a tweakable narrow block cipher mode Rik Snel
2006-08-31 12:39 ` [PATCH 6/6] crypto: a simple way of storing and checking test vectors, LRW vectors included Rik Snel
2006-09-01  3:52 ` LRW implementation, please comment Herbert Xu
2006-09-01  8:55   ` rsnel
2006-09-01 10:37     ` Herbert Xu
2006-09-02  1:00       ` LRW... v2 rsnel
2006-11-29  8:04         ` Herbert Xu
2006-09-02  1:00       ` [PATCHv2 1/6] crypto: trivial comment improvements rsnel
2006-09-02  1:00       ` [PATCHv2 2/6] crypto: benbi IV, big endian narrow block count for LRW-32-AES rsnel
2006-09-02  1:00       ` [PATCHv2 3/6] crypto: some common 128-bit block operations, nicely centralized rsnel
2006-09-02  1:00       ` [PATCHv2 4/6] crypto: table driven multiplications in GF(2^128), needed by LRW (and in the future ABL) rsnel
2006-11-26 23:56         ` Herbert Xu
2006-11-28 20:02           ` rsnel
2006-11-28 21:13             ` Herbert Xu
2006-11-28 21:17               ` rsnel
2006-11-28 22:24                 ` Herbert Xu
2006-09-02  1:00       ` rsnel [this message]
2006-09-02  1:00       ` [PATCHv2 6/6] LRW testvectors in tcrypt.[ch] rsnel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=115715883237-git-send-email-rsnel@cube.dyndns.org \
    --to=rsnel@cube.dyndns.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.