--- 3/crypto/cipher.c	2004-11-30 23:34:43.000000000 +0100
+++ final/crypto/cipher.c	2004-11-30 23:34:47.000000000 +0100
@@ -20,10 +20,7 @@
 #include <asm/scatterlist.h>
 #include "internal.h"
 #include "scatterwalk.h"
-
-typedef void (cryptfn_t)(void *, u8 *, const u8 *);
-typedef void (procfn_t)(struct crypto_tfm *, u8 *,
-                        u8*, cryptfn_t, int enc, void *, int);
+#include "lrw.h"
 
 static inline void xor_64(u8 *a, const u8 *b)
 {
@@ -39,7 +36,6 @@
 	((u32 *)a)[3] ^= ((u32 *)b)[3];
 }
 
-
 struct cbc_process_priv {
 	struct crypto_tfm *tfm;
 	int enc;
@@ -85,7 +81,7 @@
 	priv->crfn(crypto_tfm_ctx(priv->tfm), buf[0], buf[1]);
 }
 
-static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+static int setkey_generic(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
 {
 	struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
 	
@@ -214,15 +210,15 @@
 	int ret = 0;
 	struct cipher_tfm *ops = &tfm->crt_cipher;
 
-	ops->cit_setkey = setkey;
-
 	switch (tfm->crt_cipher.cit_mode) {
 	case CRYPTO_TFM_MODE_ECB:
+		ops->cit_setkey = setkey_generic;
 		ops->cit_encrypt = ecb_encrypt;
 		ops->cit_decrypt = ecb_decrypt;
 		break;
 		
 	case CRYPTO_TFM_MODE_CBC:
+		ops->cit_setkey = setkey_generic;
 		ops->cit_encrypt = cbc_encrypt;
 		ops->cit_decrypt = cbc_decrypt;
 		ops->cit_encrypt_iv = cbc_encrypt_iv;
@@ -236,6 +232,7 @@
 		break;
 		
 	case CRYPTO_TFM_MODE_CFB:
+		ops->cit_setkey = setkey_generic;
 		ops->cit_encrypt = nocrypt;
 		ops->cit_decrypt = nocrypt;
 		ops->cit_encrypt_iv = nocrypt_iv;
@@ -245,6 +242,7 @@
 		break;
 	
 	case CRYPTO_TFM_MODE_CTR:
+		ops->cit_setkey = setkey_generic;
 		ops->cit_encrypt = nocrypt;
 		ops->cit_decrypt = nocrypt;
 		ops->cit_encrypt_iv = nocrypt_iv;
@@ -253,11 +251,35 @@
 		ops->cit_decrypt_tweaks = nocrypt_tweaks;
 		break;
 
+	case CRYPTO_TFM_MODE_LRW:
+	case CRYPTO_TFM_MODE_LRW_RAW:
+		if(crypto_tfm_alg_blocksize(tfm) != 16) {
+			printk(KERN_WARNING "LRW can't be used with non-128-bit ciphers\n");
+			return -EINVAL;
+		}
+		ops->cit_tweaksize = crypto_tfm_alg_blocksize(tfm);
+		ops->cit_bytes_per_tweak = crypto_tfm_alg_blocksize(tfm);
+		ops->cit_setkey = setkey_lrw;
+		ops->cit_encrypt = nocrypt;
+		ops->cit_decrypt = nocrypt;
+		ops->cit_encrypt_iv = nocrypt_iv;
+		ops->cit_decrypt_iv = nocrypt_iv;
+		if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_LRW) {
+			ops->cit_encrypt_tweaks = lrw_encrypt;
+			ops->cit_decrypt_tweaks = lrw_decrypt;
+		} else if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_LRW_RAW) {
+			ops->cit_encrypt_tweaks = lrw_raw_encrypt;
+			ops->cit_decrypt_tweaks = lrw_raw_decrypt;	
+		} else {
+			BUG();
+		}
+		break;
 	default:
 		BUG();
 	}
 	
-	if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
+	if (ops->cit_mode == CRYPTO_TFM_MODE_CBC || ops->cit_mode == CRYPTO_TFM_MODE_LRW 
+	    || ops->cit_mode == CRYPTO_TFM_MODE_LRW_RAW) {
 	    	
 	    	switch (crypto_tfm_alg_blocksize(tfm)) {
 	    	case 8:
--- 3/crypto/api.c	2004-12-11 17:05:08.000000000 +0100
+++ final/crypto/api.c	2004-12-11 17:07:52.000000000 +0100
@@ -27,6 +27,9 @@
 static inline int crypto_cmctx_size(u32 flags) 
 {
 	switch(flags & CRYPTO_TFM_MODE_MASK) {
+		case CRYPTO_TFM_MODE_LRW:
+		case CRYPTO_TFM_MODE_LRW_RAW:
+			return 2048;
 		default:
 			return 0;
 	}
--- 3/crypto/internal.h	2004-11-23 16:53:06.000000000 +0100
+++ final/crypto/internal.h	2004-11-25 14:23:52.000000000 +0100
@@ -19,6 +19,10 @@
 #include <linux/kmod.h>
 #include <asm/kmap_types.h>
 
+typedef void (cryptfn_t)(void *, u8 *, const u8 *);
+typedef void (procfn_t)(struct crypto_tfm *, u8 *,
+                        u8*, cryptfn_t, int enc, void *, int);
+
 extern enum km_type crypto_km_types[];
 
 static inline enum km_type crypto_kmap_type(int out)
--- 3/include/linux/crypto.h	2004-11-23 16:57:16.000000000 +0100
+++ final/include/linux/crypto.h	2004-11-23 16:46:43.000000000 +0100
@@ -6,7 +6,7 @@
  * Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
  *
  * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
- * and Nettle, by Niels M�ller.
+ * and Nettle, by Niels M�ler.
  * 
  * 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
@@ -48,6 +48,8 @@
 #define CRYPTO_TFM_MODE_CBC		0x00000002
 #define CRYPTO_TFM_MODE_CFB		0x00000004
 #define CRYPTO_TFM_MODE_CTR		0x00000008
+#define CRYPTO_TFM_MODE_LRW		0x00000020
+#define CRYPTO_TFM_MODE_LRW_RAW	0x00000040
 
 #define CRYPTO_TFM_REQ_WEAK_KEY		0x00000100
 #define CRYPTO_TFM_RES_WEAK_KEY		0x00100000
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ final/crypto/lrw.c	2004-12-13 14:10:07.000000000 +0100
@@ -0,0 +1,228 @@
+/*
+ * Cryptographic API.
+ *
+ * LRW cipher mode implementation
+ * 
+ * Copyright (c) 2004, Clemens Fruhwirth <clemens@endorphin.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */    
+
+#include <linux/kernel.h>
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include "internal.h"
+#include "scatterwalk.h"
+#include "gfmulseq.h"
+
+#ifndef DEBUG
+#define LRW_DEBUG_DUMP(x,y,z) 
+#else
+#define LRW_DEBUG_DUMP(t,b,l) hexdumpTitle(t,b,l);
+
+static void
+hexdumpTitle(char *title, unsigned char *buf, unsigned int len)
+{
+	printk("%s",title);
+        while (len--)
+                printk("%02x", *buf++);
+
+        printk("\n");
+}
+#endif
+
+struct lrw_info {
+	struct crypto_tfm *tfm;
+	cryptfn_t *fn;
+};
+
+struct lrw_tweak_cooks_info {
+	u128 startN;
+	u128 currentN;
+	int stripesize;
+	u64 *cooked_tweaks;
+	int cooked_tweaks_idx;
+	u64 *negTab;
+};
+
+static void lrw_generate_table(const char *xkey2, u64 *negTab) {
+	u64 rpol[] = { 0x0ULL, 0x87ULL }; /* reduction polynomial as defined by LRW specs */
+	u64 *key2 = (u64 *)xkey2;
+	key2[0] = be64_to_cpu(key2[0]);
+	key2[1] = be64_to_cpu(key2[1]);
+	GFMulGenTab(key2,rpol,negTab);
+}
+
+/* Note that the tweaks are not the tweaksdasd*/
+
+static void lrw_tweak_cook(void *priv, int sg, void **dpatchlist) 
+{
+	struct lrw_tweak_cooks_info *lta = (struct lrw_tweak_cooks_info *)priv;
+	u64 *raw_tweak = dpatchlist[0];
+	
+	if(lta->stripesize == 0) {
+		copy128(lta->startN,raw_tweak);
+		copy128(lta->currentN,raw_tweak);
+		lta->stripesize = 1;
+		return;
+	}
+	add128(lta->currentN,1);
+	if(equal128(lta->currentN, raw_tweak)) {
+		lta->stripesize++;	
+	} else {
+		GFMulSeq(lta->startN, (lta->cooked_tweaks)+lta->cooked_tweaks_idx, lta->stripesize, lta->negTab);
+		copy128(lta->startN,raw_tweak);
+		copy128(lta->currentN,raw_tweak);
+		lta->cooked_tweaks_idx += I1(lta->stripesize);
+		lta->stripesize = 1;
+	}	
+}
+
+/* Helper for clients of this mode */
+void lrw_generate_tweak_seq(struct crypto_tfm *tfm, u64 *start, u64 *buf, u32 length)
+{
+	GFMulSeq(start, buf, length, (u64 *)crypto_tfm_cmctx(tfm));
+}
+EXPORT_SYMBOL_GPL(lrw_generate_tweak_seq);
+
+static void lrw_one_pass(void *priv,int sg, void **dpatchlist)
+{
+	struct lrw_info *lrw = (struct lrw_info *)priv;
+	u8 *src = dpatchlist[0];
+	u8 *dst = dpatchlist[1];
+	u8 *tweaks = dpatchlist[2];
+	LRW_DEBUG_DUMP("P:",src,16);
+	LRW_DEBUG_DUMP("T:",tweaks,16);
+
+	((u64 *)dst)[0] = ((u64 *)src)[0] ^ ((u64 *)tweaks)[0];
+	((u64 *)dst)[1] = ((u64 *)src)[1] ^ ((u64 *)tweaks)[1];
+
+	LRW_DEBUG_DUMP("P^T:",dst,16);
+
+	lrw->fn(crypto_tfm_ctx(lrw->tfm),dst,dst);
+
+	LRW_DEBUG_DUMP("Enc(P^T):",dst,16);
+
+	((u64 *)dst)[0] ^= ((u64 *)tweaks)[0];
+	((u64 *)dst)[1] ^= ((u64 *)tweaks)[1];
+}
+
+int lrw_raw_encrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaksg)
+{
+	struct lrw_info callinfo = {
+		.tfm = tfm,
+		.fn = tfm->__crt_alg->cra_cipher.cia_encrypt,
+	};
+	scatterwalk_walker_generic(lrw_one_pass, &callinfo, nbytes/16, 3, src, 16, 0, dst, 16, 1, tweaksg, 16, 0);
+	return 0;
+}
+
+int lrw_raw_decrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaksg)
+{
+	struct lrw_info callinfo = {
+		.tfm = tfm,
+		.fn = tfm->__crt_alg->cra_cipher.cia_decrypt,
+	};
+	scatterwalk_walker_generic(lrw_one_pass, &callinfo, nbytes/16, 3, src, 16, 0, dst, 16, 1, tweaksg, 16, 0);
+	return 0;
+}
+
+int lrw_template(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *raw_tweaks,
+                          int (*rawfunction)(struct crypto_tfm *,
+                                             struct scatterlist *,
+                                             struct scatterlist *,
+                                             unsigned int, 
+                                             struct scatterlist *))
+{
+	int r;
+	struct scatterlist cooked_tweaks_sg = {NULL, };
+	u128_alloc(currentN);
+	u128_alloc(startN);
+	u64 *cooked_tweaks = kmalloc(nbytes,GFP_KERNEL);
+	
+	struct lrw_tweak_cooks_info recipe = {
+		.startN = startN,
+		.currentN = currentN,
+		.stripesize = 0,
+		.cooked_tweaks = cooked_tweaks,
+		.cooked_tweaks_idx = 0,
+		.negTab = crypto_tfm_cmctx(tfm),
+	};
+	
+	if(cooked_tweaks == NULL)
+		return -ENOMEM;
+	
+	scatterwalk_walker_generic(lrw_tweak_cook, &recipe, nbytes/16, 1, raw_tweaks, 16, 0);
+	GFMulSeq(recipe.startN, recipe.cooked_tweaks+recipe.cooked_tweaks_idx, recipe.stripesize, recipe.negTab);
+		
+	cooked_tweaks_sg.page = virt_to_page(cooked_tweaks);
+	cooked_tweaks_sg.offset = offset_in_page(cooked_tweaks);
+	cooked_tweaks_sg.length = nbytes;
+	
+	r = rawfunction(tfm,dst,src,nbytes,&cooked_tweaks_sg);
+	kfree(cooked_tweaks);
+	
+	return r;
+}
+
+int lrw_encrypt(struct crypto_tfm *tfm, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes, 
+                    struct scatterlist *tweaksg)
+{
+	return lrw_template(tfm,dst,src,nbytes,tweaksg,lrw_raw_encrypt);
+}
+
+int lrw_decrypt(struct crypto_tfm *tfm, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes, 
+                    struct scatterlist *tweaksg)
+{
+	return lrw_template(tfm,dst,src,nbytes,tweaksg,lrw_raw_decrypt);
+}
+
+int setkey_lrw(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+	struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+	int bsize = crypto_tfm_alg_blocksize(tfm);
+	int r = -EINVAL;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "setkey_lrw: given keylen %d, wanted min %d, wanted max %d\n",keylen,cia->cia_min_keysize + bsize,cia->cia_max_keysize + bsize);
+#endif
+	if (keylen < (cia->cia_min_keysize + bsize)
+		|| keylen > (cia->cia_max_keysize + bsize)) {
+		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	r = cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen-bsize,
+                            &tfm->crt_flags);
+	if (r < 0) 
+		return r;
+
+	lrw_generate_table(key+keylen-bsize,crypto_tfm_cmctx(tfm));
+	return r;
+}
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ final/crypto/lrw.h	2004-11-23 16:46:13.000000000 +0100
@@ -0,0 +1,45 @@
+/*
+ * Cryptographic API.
+ *
+ * LRW cipher mode implementation
+ * 
+ * Copyright (c) 2004, Clemens Fruhwirth <clemens@endorphin.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */    
+    
+int lrw_raw_encrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaksg);
+int lrw_encrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaks);  
+int lrw_raw_decrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaksg);
+int lrw_decrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaksg);
+int setkey_lrw(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen);
+
+/* 
+ * Unfortunately LRW requires spaghetti coding otherwise the performance of 
+ * this mode is unreasonable 
+ */
+void lrw_generate_tweak_seq(struct crypto_tfm *tfm, u64 *start, u64 *buf, u32 length);
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ final/crypto/gfmulseq.c	2004-12-13 13:53:47.000000000 +0100
@@ -0,0 +1,219 @@
+	/*
+ * Efficient Generation Of Arithmetic Sequences of Multiplications in GF(2^128)
+ *
+ * Copyright 2004, Clemens Fruhwirth <clemens@endorphin.org>
+ *
+ * Go to http://clemens.endorphin.org/publications for documentation.
+ * Otherwise, you will have no chance to understand the mathematical
+ * background behind this code.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include "gfmulseq.h"
+
+#define u64msbmask (1ULL << 63)
+
+#define xor128(op, arg) 				\
+	do { 						\
+		(op)[0] = (op)[0] ^ (arg)[0]; 		\
+		(op)[1] = (op)[1] ^ (arg)[1]; 		\
+	} while(0)
+
+#define lsr128(n,shift) 							\
+	do {									\
+		(n)[1] = (n)[1] >> shift | (n)[0] << (bits/2-(shift));		\
+		(n)[0] = (n)[0] >> shift;					\
+	} while(0)
+
+#define lsl128(n,shift)							\
+	do {								\
+		(n)[0] = (n)[0] << shift | (n)[1] >> (bits/2-(shift));	\
+		(n)[1] = (n)[1] << 1;					\
+	} while(0)
+
+#define msb128(n) (((n)[0] & u64msbmask)?0x1:0x0)
+
+#define lsb128(n) ((n)[1] & 0x1)
+
+#define zero128(pointer) memset((void *)(pointer),0,sizeof(u64)*u64factor);
+	
+#define setN(negTab,i,value)					\
+	do {							\
+		(negTab)[I1(i)] = cpu_to_be64((value)[0]);	\
+		(negTab)[I2(i)] = cpu_to_be64((value)[1]);	\
+	} while(0)
+
+/* 
+ * GF Multiplication Base Algorithm 
+ */
+	
+void GFMulBase(u128 callersN, u128 GF, u128_t negTab) {
+	int want=1;
+	int i=0;
+	/* Copy N, so lsl does not destroy caller's copy */
+	u128_alloc(N);
+	copy128(N,callersN);
+
+	zero128(GF);
+	for(i=0;i<bits;i++) {
+		if (msb128(N) == want) {
+			xor128(GF,&negTab[I1(bits-1-i)]);
+			want = want?0:1;
+		}
+		lsl128(N,1);
+	}
+}
+
+static inline void findAlignment(u128 callersN, int value, int *align) {
+	int i;
+	/* Copy N, so lsr does not destroy caller's copy */
+	u128_alloc(N);
+	copy128(N,callersN);
+
+	lsr128(N,*align);
+	for(i=*align;i<bits;i++) {
+		if (lsb128(N) != value) {
+			*align = i;
+			return;
+		}
+		lsr128(N,1);
+	}
+	*align = bits;
+}
+
+/* GF Multiplication Aligned 
+ * Generates min(length,1<<pow2) GF multiplication results,
+ * GF_i = GF_0/n*(n+i), when pow2 is the alignment of N in base 2.
+ */
+
+void GFMulAligned(u128 currentN, u64 **callersCurrentGF, u64 *negTab, int pow2, int *length) {
+	int i;			// Outer control loop counter
+	int j;			// Inner control loop counter
+	int revp;		// Inner control loop reverse pointer
+	int curp=0;		// Destination pointer for next computation
+	u64 *currentGF = *callersCurrentGF;	// pointer to base GF
+	u64 addPoly[2];		// Inner loop's addition polynomial 
+	
+#ifdef DEBUG
+	printf("bulk: %d %d\n",pow2,*length);
+	print128(currentN);
+#endif
+	for(i=0; i<pow2 && *length; i++) {
+		/* Reverse pointer */
+		revp = 1 << i;
+
+#define min(a,b) (a)<(b)?(a):(b)
+		/* 
+		 * Inner loop control variable, either exhaust all data
+		 * available by the reverse pointer, or clip by the length
+		 */
+		j = min(revp, *length);
+#undef min
+		/* processing polynomial */
+		addPoly[0] = negTab[I1(i)];
+		addPoly[1] = negTab[I2(i)];
+
+		/* subtract before loop, otherwise j would be zero */
+		*length -= j;
+
+		while(j--) {
+			curp++;
+			revp--;
+			currentGF[I1(curp)] = currentGF[I1(revp)] ^ addPoly[0];
+			currentGF[I2(curp)] = currentGF[I2(revp)] ^ addPoly[1];
+		}
+	}
+	/* Update callers variables */	
+	/* set pointer of the caller to the new base GF */
+	*callersCurrentGF = &currentGF[I1(curp)];
+	/* update N by adding total number of generated GFs */
+	add128(currentN,curp);
+#ifdef DEBUG
+	printf("bulk generated %d\n",curp);
+#endif
+}
+
+/*
+ * GF Multiplication Negative Step
+ * computes GF_2 = GF_1 / n * (n+1)
+ */
+
+void GFMulNStep(u64 *currentN, u64 *currentGF, u64 *negTab, int align) {
+#ifdef DEBUG
+	printf("negative step at:");
+	print128(currentN);
+#endif
+	currentGF[I1(1)] = currentGF[I1(0)] ^ negTab[I1(align)];
+	currentGF[I2(1)] = currentGF[I2(0)] ^ negTab[I2(align)];
+}
+
+/*
+ * GF Multiplication Sequence
+ * Generates an arithmetic sequence of GF multiplications
+ */
+
+void GFMulSeq(u64 *callersN, u64 *dst, int length, u64 *negTab)
+{
+	u64 *currentGF = dst;
+	u128_alloc(currentN);
+	int alignOfN=0;
+
+	copy128(currentN,callersN);
+	GFMulBase(currentN, currentGF, negTab);
+	length--;
+	
+	if(!length) return;
+	
+	findAlignment(currentN,0,&alignOfN);
+	if(alignOfN != 0) {
+		GFMulAligned(currentN, &currentGF, negTab, alignOfN, &length);
+	}
+	while(1) {
+		if(!length) return;
+			findAlignment(currentN,1,&alignOfN);
+			
+			GFMulNStep(currentN, currentGF, negTab, alignOfN);
+			add128(currentN,1);
+			currentGF = &currentGF[I1(1)];	
+			length--;
+		if(!length) return;
+			/* 
+			 * alignedBulk takes alignment of Zero at end as parameter,
+			 * but we don't need to recompute the value since after a negative
+			 * step the previously aligned ones are guaranteed to become zeros,
+			 * so alignOfN == findAlignment(current,0).
+			 */
+			GFMulAligned(currentN, &currentGF, negTab, alignOfN, &length);
+		alignOfN++; /* Hint our knowledge to findAlignment */
+	}
+}
+
+/* 
+ * genNegTab: generate negative-logic table, that is: 
+ * Table with GF multiplication results from 2^(i+1)-1, or in otherwords, all
+ * bits set till bit i.
+ */
+
+void GFMulGenTab(u128 key2, u128 rpol, u128_t negTab) {
+	u128_alloc(key2Control);
+	u128_alloc(res);
+	int i;
+		
+	copy128(key2Control,key2);
+	copy128(res,key2);
+
+	setN(negTab,0,key2);
+	for(i=1; i < bits; i++) {
+		if(msb128(key2Control)) {
+			lsl128(key2Control,1);
+			xor128(key2Control,rpol);
+		}
+		else
+			lsl128(key2Control,1);
+		xor128(res,key2Control);
+		setN(negTab,i,res);
+	}
+}
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ final/crypto/gfmulseq.h	2004-11-25 14:19:56.000000000 +0100
@@ -0,0 +1,74 @@
+/*
+ * Efficient Generation Of Arithmetic Sequences of Multiplications in GF(2^128)
+ *
+ * Copyright 2004, Clemens Fruhwirth <clemens@endorphin.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * Go to http://clemens.endorphin.org/publications for documentation.
+ * Otherwise, you will have no chance to understand the mathematical
+ * background behind this code.
+ */
+
+#ifndef __GFMULSEQ_H__
+#define __GFMULSEQ_H__
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+#define print128(n) do { 						\
+	char *__print128_p = (char *)n;					\
+	int __print128_i;						\
+	for(__print128_i = 0; __print128_i<16; __print128_i++)	\
+		printk("%02hhx",*(__print128_p+__print128_i));		\
+	printk("\n"); 							\
+} while(0) 
+
+typedef u64 *u128;
+typedef u64 *u128_t;
+
+#define u128_alloc(VAR) u64 _ ## VAR ## _[2]; u128 VAR = _ ## VAR ## _
+
+#define bits 128
+#define u64factor 2
+#define I1(x) ((x)*u64factor)
+#define I2(x) ((x)*u64factor+1)
+
+#define copy128(dst,src)			\
+	do {					\
+		(dst)[0] = (src)[0];		\
+		(dst)[1] = (src)[1];		\
+	} while(0)
+
+#define add128(dst,oper)						\
+	do {								\
+		u64 scratch = (dst)[1] + (oper);			\
+		if(scratch < (dst)[1] && scratch < (oper)) 		\
+			(dst)[0]++;					\
+		(dst)[1] = scratch;					\
+	} while(0)
+	
+#define equal128(op1,op2) \
+	(((op1)[0] == (op2)[0]) && ((op1)[1] == (op2)[1]))
+	
+#define cpu_to_be128(op1) \
+	do { 			\
+		(op1)[0] = cpu_to_be64((op1)[0]); \
+		(op1)[1] = cpu_to_be64((op1)[1]); \
+	} while(0)
+
+#define be128_to_cpu(op1) \
+	do { 			\
+		(op1)[0] = be64_to_cpu((op1)[0]); \
+		(op1)[1] = be64_to_cpu((op1)[1]); \
+	} while(0)
+
+
+void GFMulBase(u128 callersN, u128 GF, u128_t negTab);
+void GFMulSeq(u64 *currentN, u64 *dst, int length, u64 *negTab);
+void GFMulGenTab(u128 key2, u128 rpol, u128_t negTab);
+
+#endif
--- 3/crypto/Makefile	2004-11-23 16:44:20.000000000 +0100
+++ final/crypto/Makefile	2004-11-23 16:46:08.000000000 +0100
@@ -4,7 +4,7 @@
 
 proc-crypto-$(CONFIG_PROC_FS) = proc.o
 
-obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o \
+obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o lrw.o gfmulseq.o \
 			$(proc-crypto-y)
 
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
--- 3/crypto/tcrypt.c	2004-12-11 22:54:25.000000000 +0100
+++ final/crypto/tcrypt.c	2004-12-11 22:51:50.000000000 +0100
@@ -50,8 +50,9 @@
 */
 #define ENCRYPT 1
 #define DECRYPT 0
-#define MODE_ECB 1
-#define MODE_CBC 0
+#define MODE_ECB 0
+#define MODE_CBC 1
+#define MODE_LRW 2
 
 static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
 
@@ -265,19 +266,38 @@
 	char *key;
 	struct cipher_testvec *cipher_tv;
 	struct scatterlist sg[8];
+	struct scatterlist tweaks[1];
 	char e[11], m[4];
 
 	if (enc == ENCRYPT)
 	        strncpy(e, "encryption", 11);
 	else
         	strncpy(e, "decryption", 11);
-	if (mode == MODE_ECB)
-        	strncpy(m, "ECB", 4);
-	else
-        	strncpy(m, "CBC", 4);
-
+	
+	switch (mode) {
+	case MODE_ECB:
+		tfm = crypto_alloc_tfm (algo, CRYPTO_TFM_MODE_ECB);
+		strncpy(m, "ECB", 4);
+		break;
+	case MODE_CBC:
+		tfm = crypto_alloc_tfm (algo, CRYPTO_TFM_MODE_CBC);
+		strncpy(m, "CBC", 4);
+		break;
+        case MODE_LRW:
+		tfm = crypto_alloc_tfm (algo, CRYPTO_TFM_MODE_LRW);
+		strncpy(m,"LRW",4);
+		break;
+	default:
+		BUG();
+		return;
+	}
 	printk("\ntesting %s %s %s \n", algo, m, e);
 
+	if (tfm == NULL) {
+		printk("failed to load transform for %s %s\n", algo, m);
+		return;
+	}
+
 	tsize = sizeof (struct cipher_testvec);	
 	tsize *= tcount;
 	
@@ -286,19 +306,8 @@
 		       TVMEMSIZE);
 		return;
 	}
-
 	memcpy(tvmem, template, tsize);
 	cipher_tv = (void *) tvmem;
-
-	if (mode) 
-		tfm = crypto_alloc_tfm (algo, 0);
-	else 
-		tfm = crypto_alloc_tfm (algo, CRYPTO_TFM_MODE_CBC);
-	
-	if (tfm == NULL) {
-		printk("failed to load transform for %s %s\n", algo, m);
-		return;
-	}
 	
 	j = 0;
 	for (i = 0; i < tcount; i++) {
@@ -324,18 +333,34 @@
 			sg[0].page = virt_to_page(p);
 			sg[0].offset = offset_in_page(p);
 			sg[0].length = cipher_tv[i].ilen;
-	
-			if (!mode) {
+
+			switch(mode) {
+			case MODE_CBC:
 				crypto_cipher_set_iv(tfm, cipher_tv[i].iv,
-					crypto_tfm_alg_ivsize (tfm));
+						     crypto_tfm_alg_ivsize (tfm));
+				/* fall-through intentional */
+			case MODE_ECB:
+				if (enc)
+					ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);
+				else
+					ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);
+				break;
+			case MODE_LRW:
+				{
+					u64 *hosttweak = (u64 *)cipher_tv[i].tweak;
+					hosttweak[0] = be64_to_cpu(hosttweak[0]);
+					hosttweak[1] = be64_to_cpu(hosttweak[1]);
+					tweaks[0].page = virt_to_page(cipher_tv[i].tweak);
+					tweaks[0].offset = offset_in_page(cipher_tv[i].tweak);
+					tweaks[0].length = cipher_tv[i].tlen;
+					if (enc)
+						ret = crypto_cipher_encrypt_tweaks(tfm, sg, sg, cipher_tv[i].ilen, tweaks);
+					else
+						ret = crypto_cipher_decrypt_tweaks(tfm, sg, sg, cipher_tv[i].ilen, tweaks);
+					break;
+				}
 			}
-		
-			if (enc)
-				ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);
-			else
-				ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);
-			
-				
+
 			if (ret) {
 				printk("%s () failed flags=%x\n", e, tfm->crt_flags);
 				goto out;
@@ -384,16 +409,28 @@
 				sg[k].length = cipher_tv[i].tap[k];
 			}
 			
-			if (!mode) {
+			switch(mode) {
+			case MODE_CBC:
 				crypto_cipher_set_iv(tfm, cipher_tv[i].iv,
-						crypto_tfm_alg_ivsize (tfm));
+						     crypto_tfm_alg_ivsize (tfm));
+				/* fall-through intentional */
+			case MODE_ECB:
+				if (enc)
+					ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);
+				else
+					ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);
+				break;
+			case MODE_LRW:
+				tweaks[0].page = virt_to_page(cipher_tv[i].tweak);
+				tweaks[0].offset = offset_in_page(cipher_tv[i].tweak);
+				tweaks[0].length = cipher_tv[i].tlen;
+				if (enc)
+					ret = crypto_cipher_encrypt_tweaks(tfm, sg, sg, cipher_tv[i].ilen, tweaks);
+				else
+					ret = crypto_cipher_decrypt_tweaks(tfm, sg, sg, cipher_tv[i].ilen, tweaks);
+				break;
 			}
-			
-			if (enc)
-				ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);
-			else
-				ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);
-			
+
 			if (ret) {
 				printk("%s () failed flags=%x\n", e, tfm->crt_flags);
 				goto out;
@@ -659,6 +696,9 @@
 		test_cipher ("aes", MODE_ECB, ENCRYPT, aes_enc_tv_template, AES_ENC_TEST_VECTORS);
 		test_cipher ("aes", MODE_ECB, DECRYPT, aes_dec_tv_template, AES_DEC_TEST_VECTORS);
 
+		//AES-LRW
+		test_cipher ("aes", MODE_LRW, ENCRYPT, aes_lrw_enc_tv_template, AES_LRW_ENC_TEST_VECTORS);
+
 		//CAST5
 		test_cipher ("cast5", MODE_ECB, ENCRYPT, cast5_enc_tv_template, CAST5_ENC_TEST_VECTORS);
 		test_cipher ("cast5", MODE_ECB, DECRYPT, cast5_dec_tv_template, CAST5_DEC_TEST_VECTORS);
--- 3/crypto/tcrypt.h	2004-12-11 22:54:25.000000000 +0100
+++ final/crypto/tcrypt.h	2004-12-11 22:51:50.000000000 +0100
@@ -52,6 +52,8 @@
 	char iv[MAX_IVLEN];
 	char input[48];
 	unsigned char ilen;
+	char tweak[48];
+	unsigned char tlen;
 	char result[48];
 	unsigned char rlen;
 	int np;
@@ -1780,6 +1782,82 @@
 	},
 };
 
+#define AES_LRW_ENC_TEST_VECTORS 7
+
+struct cipher_testvec aes_lrw_enc_tv_template[] = {
+	{
+		.key = { 0x45, 0x62, 0xac, 0x25, 0xf8, 0x28, 0x17, 0x6d, 0x4c, 0x26, 0x84, 0x14, 0xb5, 0x68, 0x01, 0x85,
+			 0x25, 0x8e, 0x2a, 0x05, 0xe7, 0x3e, 0x9d, 0x03, 0xee, 0x5a, 0x83, 0x0c, 0xcc, 0x09, 0x4c, 0x87 },
+		.klen = 32,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0xf1, 0xb2, 0x73, 0xcd, 0x65, 0xa3, 0xdf, 0x5f, 0xe9, 0x5d, 0x48, 0x92, 0x54, 0x63, 0x4e, 0xb8 },
+		.rlen = 16,
+	}, {
+		.key = { 0x59, 0x70, 0x47, 0x14, 0xf5, 0x57, 0x47, 0x8c, 0xd7, 0x79, 0xe8, 0x0f, 0x54, 0x88, 0x79, 0x44,
+			 0x0d, 0x48, 0xf0, 0xb7, 0xb1, 0x5a, 0x53, 0xea, 0x1c, 0xaa, 0x6b, 0x29, 0xc2, 0xca, 0xfb, 0xaf },
+		.klen = 32,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0x00, 0xc8, 0x2b, 0xae, 0x95, 0xbb, 0xcd, 0xe5, 0x27, 0x4f, 0x07, 0x69, 0xb2, 0x60, 0xe1, 0x36 },
+		.rlen = 16,
+	}, {
+		.key = { 0xd8, 0x2a, 0x91, 0x34, 0xb2, 0x6a, 0x56, 0x50, 0x30, 0xfe, 0x69, 0xe2, 0x37, 0x7f, 0x98, 0x47,
+			 0xcd, 0xf9, 0x0b, 0x16, 0x0c, 0x64, 0x8f, 0xb6, 0xb0, 0x0d, 0x0d, 0x1b, 0xae, 0x85, 0x87, 0x1f },
+		.klen = 32,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0x76, 0x32, 0x21, 0x83, 0xed, 0x8f, 0xf1, 0x82, 0xf9, 0x59, 0x62, 0x03, 0x69, 0x0e, 0x5e, 0x01 },
+		.rlen = 16,
+	}, {
+		.key = { 0x0f, 0x6a, 0xef, 0xf8, 0xd3, 0xd2, 0xbb, 0x15, 0x25, 0x83, 0xf7, 0x3c, 0x1f, 0x01, 0x28, 0x74, 0xca, 0xc6, 0xbc, 0x35, 0x4d, 0x4a, 0x65, 0x54,
+			 0x90, 0xae, 0x61, 0xcf, 0x7b, 0xae, 0xbd, 0xcc, 0xad, 0xe4, 0x94, 0xc5, 0x4a, 0x29, 0xae, 0x70 },
+		.klen = 40,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0x9c, 0x0f, 0x15, 0x2f, 0x55, 0xa2, 0xd8, 0xf0, 0xd6, 0x7b, 0x8f, 0x9e, 0x28, 0x22, 0xbc, 0x41 },
+		.rlen = 16,
+	}, {
+		.key = { 0x8a, 0xd4, 0xee, 0x10, 0x2f, 0xbd, 0x81, 0xff, 0xf8, 0x86, 0xce, 0xac, 0x93, 0xc5, 0xad, 0xc6, 0xa0, 0x19, 0x07, 0xc0, 0x9d, 0xf7, 0xbb, 0xdd,
+			 0x52, 0x13, 0xb2, 0xb7, 0xf0, 0xff, 0x11, 0xd8, 0xd6, 0x08, 0xd0, 0xcd, 0x2e, 0xb1, 0x17, 0x6f },
+		.klen = 40,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0xd4, 0x27, 0x6a, 0x7f, 0x14, 0x91, 0x3d, 0x65, 0xc8, 0x60, 0x48, 0x02, 0x87, 0xe3, 0x34, 0x06 },
+		.rlen = 16,
+	}, {
+		.key = { 0xf8, 0xd4, 0x76, 0xff, 0xd6, 0x46, 0xee, 0x6c, 0x23, 0x84, 0xcb, 0x1c, 0x77, 0xd6, 0x19, 0x5d, 0xfe, 0xf1, 0xa9, 0xf3, 0x7b, 0xbc, 0x8d, 0x21, 0xa7, 0x9c, 0x21, 0xf8, 0xcb, 0x90, 0x02, 0x89,
+		 	 0xa8, 0x45, 0x34, 0x8e, 0xc8, 0xc5, 0xb5, 0xf1, 0x26, 0xf5, 0x0e, 0x76, 0xfe, 0xfd, 0x1b, 0x1e },
+		.klen = 48,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0xbd, 0x06, 0xb8, 0xe1, 0xdb, 0x98, 0x89, 0x9e, 0xc4, 0x98, 0xe4, 0x91, 0xcf, 0x1c, 0x70, 0x2b },
+		.rlen = 16,
+	}, {
+		.key = { 0xfb, 0x76, 0x15, 0xb2, 0x3d, 0x80, 0x89, 0x1d, 0xd4, 0x70, 0x98, 0x0b, 0xc7, 0x95, 0x84, 0xc8, 0xb2, 0xfb, 0x64, 0xce, 0x60, 0x97, 0x87, 0x8d, 0x17, 0xfc, 0xe4, 0x5a, 0x49, 0xe8, 0x30, 0xb7,
+			 0x6e, 0x78, 0x17, 0xe7, 0x2d, 0x5e, 0x12, 0xd4, 0x60, 0x64, 0x04, 0x7a, 0xf1, 0x2f, 0x9e, 0x0c },
+		.klen = 48,
+		.tweak = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 },
+		.tlen = 16,
+		.input = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+		.ilen = 16,
+		.result = { 0x5b, 0x90, 0x8e, 0xc1, 0xab, 0xdd, 0x67, 0x5f, 0x3d, 0x69, 0x8a, 0x95, 0x53, 0xc8, 0x9c, 0xe5 },
+		.rlen = 16,
+	}
+};
+
 /* Cast5 test vectors from RFC 2144 */
 #define CAST5_ENC_TEST_VECTORS	3
 #define CAST5_DEC_TEST_VECTORS	3
@@ -2613,3 +2691,4 @@
 };
 
 #endif	/* _CRYPTO_TCRYPT_H */
+
