This is the core of my LRW patch. Added test vectors.
http://grouper.ieee.org/groups/1619/email/pdf00017.pdf
Please notice, that this is not a patch for dm-crypt. I will
post a nice splitted patch set for dm later that day.

Signed-off-by: Fruhwirth Clemens <[EMAIL PROTECTED]>

--- 3/crypto/cipher.c   2005-01-24 11:35:58.994317520 +0100
+++ final/crypto/cipher.c       2005-01-24 11:42:16.682900128 +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;
        
@@ -258,15 +254,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;
@@ -280,6 +276,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;
@@ -289,6 +286,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;
@@ -297,11 +295,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      2005-01-20 10:16:06.000000000 +0100
+++ final/crypto/api.c  2005-01-24 11:42:16.683899976 +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 2005-01-20 10:16:06.000000000 +0100
+++ final/crypto/internal.h     2005-01-24 11:42:16.684899824 +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    2005-01-24 11:33:34.498284256 +0100
+++ final/include/linux/crypto.h        2005-01-24 11:42:16.684899824 +0100
@@ -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  2005-01-24 12:50:41.620854704 +0100
@@ -0,0 +1,262 @@
+/*
+ * Cryptographic API.
+ *
+ * LRW cipher mode implementation
+ * 
+ * Copyright (c) 2004, Clemens Fruhwirth <[EMAIL PROTECTED]>
+ *
+ * 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);
+}
+
+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 walk_info lrw_walk_infos[3] = {
+               [0].sg = src, 
+               [0].stepsize = 16, 
+               [0].ioflag = 0, 
+               [0].buf = (char[16]){},
+               [1].sg = dst, 
+               [1].stepsize = 16, 
+               [1].ioflag = 1, 
+               [1].buf = (char[16]){},
+               [2].sg = tweaksg, 
+               [2].stepsize = 16, 
+               [2].ioflag = 0, 
+               [2].buf = (char[16]){},
+       };
+            
+       struct lrw_info callinfo = {
+               .tfm = tfm,
+               .fn = tfm->__crt_alg->cra_cipher.cia_encrypt,
+       };
+       scatterwalk_walker_generic(lrw_one_pass, &callinfo, nbytes/16, 3, 
lrw_walk_infos);
+       return 0;
+}
+
+int lrw_raw_decrypt(struct crypto_tfm *tfm,
+                          struct scatterlist *dst,
+                          struct scatterlist *src,
+                          unsigned int nbytes, struct scatterlist *tweaksg)
+{
+       struct walk_info lrw_walk_infos[3] = {
+               [0].sg = src, 
+               [0].stepsize = 16, 
+               [0].ioflag = 0, 
+               [0].buf = (char[16]){},
+               [1].sg = dst, 
+               [1].stepsize = 16, 
+               [1].ioflag = 1, 
+               [1].buf = (char[16]){},
+               [2].sg = tweaksg, 
+               [2].stepsize = 16, 
+               [2].ioflag = 0, 
+               [2].buf = (char[16]){},
+       };
+       struct lrw_info callinfo = {
+               .tfm = tfm,
+               .fn = tfm->__crt_alg->cra_cipher.cia_decrypt,
+       };
+       scatterwalk_walker_generic(lrw_one_pass, &callinfo, nbytes/16, 3, 
lrw_walk_infos);
+       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 walk_info cook_walk_info[1] = {
+               [0].sg = raw_tweaks,
+               [0].stepsize = 16,
+               [0].ioflag = 0,
+               [0].buf = (char[16]){},
+       };
+
+       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, 
cook_walk_info);
+       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  2005-01-24 12:51:03.290560408 +0100
@@ -0,0 +1,45 @@
+/*
+ * Cryptographic API.
+ *
+ * LRW cipher mode implementation
+ * 
+ * Copyright (c) 2004, Clemens Fruhwirth <[EMAIL PROTECTED]>
+ *
+ * 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     2005-01-24 12:44:51.627061848 +0100
@@ -0,0 +1,219 @@
+/*
+ * Efficient Generation Of Arithmetic Sequences of Multiplications in GF(2^128)
+ *
+ * Copyright 2004, Clemens Fruhwirth <[EMAIL PROTECTED]>
+ *
+ * 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     2005-01-24 11:42:16.687899368 +0100
@@ -0,0 +1,74 @@
+/*
+ * Efficient Generation Of Arithmetic Sequences of Multiplications in GF(2^128)
+ *
+ * Copyright 2004, Clemens Fruhwirth <[EMAIL PROTECTED]>
+ *
+ * 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   2005-01-20 10:16:06.000000000 +0100
+++ final/crypto/Makefile       2005-01-24 11:42:16.688899216 +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   2005-01-20 10:16:06.000000000 +0100
+++ final/crypto/tcrypt.c       2005-01-24 11:42:16.689899064 +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   2005-01-20 10:16:06.000000000 +0100
+++ final/crypto/tcrypt.h       2005-01-24 11:42:16.692898608 +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 */
+
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to