diff -ru --new-file util-linux-2.11y/mount/Makefile util-linux-AES/mount/Makefile
--- util-linux-2.11y/mount/Makefile	Tue Nov 26 10:15:57 2002
+++ util-linux-AES/mount/Makefile	Thu Feb  6 23:31:03 2003
@@ -24,7 +24,6 @@
 
 MAYBE = pivot_root swapoff
 
-LO_OBJS = lomount.o $(LIB)/xstrncpy.o
 NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o
 GEN_FILES = nfsmount.h nfsmount_xdr.c nfsmount_clnt.c
 
@@ -44,22 +43,30 @@
 
 mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \
        mount_guess_fstype.o get_label_uuid.o mount_by_label.o getusername.o \
-       $(LIB)/setproctitle.o $(LIB)/env.o $(NFS_OBJS) $(LO_OBJS)
+       $(LIB)/setproctitle.o $(LIB)/env.o $(NFS_OBJS) lomount.o loumount.o \
+       sha512.o rmd160.o aes.o $(LIB)/xstrncpy.o
+
 	$(LINK) $^ -o $@
 
 umount: umount.o fstab.o sundries.o realpath.o mntent.o getusername.o \
-	get_label_uuid.o version.o $(LIB)/env.o $(LO_OBJS)
+	get_label_uuid.o version.o $(LIB)/env.o loumount.o
 	$(LINK) $^ -o $@
 
-swapon:	swapon.o version.o
+swapon:	swapon.o version.o sha512.o
 	$(LINK) $^ -o $@
 
 main_losetup.o: lomount.c
 	$(COMPILE) -DMAIN lomount.c -o $@
 
-losetup: main_losetup.o $(LIB)/xstrncpy.o
+losetup: main_losetup.o loumount.o $(LIB)/xstrncpy.o sha512.o rmd160.o aes.o
 	$(LINK) $^ -o $@
 
+aes.o lomount.o main_losetup.o: aes.h
+
+rmd160.o lomount.o main_losetup.o: rmd160.h
+
+sha512.o lomount.o main_losetup.o: sha512.h
+
 mount.o umount.o nfsmount.o losetup.o fstab.o realpath.o sundries.o: sundries.h
 
 mount.o umount.o fstab.o sundries.o: fstab.h
@@ -72,9 +79,9 @@
 
 mount.o umount.o getusername.o: getusername.h
 
-mount.o umount.o losetup.o lomount.o: lomount.h loop.h
+mount.o umount.o losetup.o lomount.o loumount.o: lomount.h loop.h
 
-swapon.o: swap_constants.h swapargs.h
+swapon.o: swap_constants.h swapargs.h loop.h
 
 sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h
 
diff -ru --new-file util-linux-2.11y/mount/aes.c util-linux-AES/mount/aes.c
--- util-linux-2.11y/mount/aes.c	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/aes.c	Thu Feb  6 23:22:05 2003
@@ -0,0 +1,1397 @@
+// I retain copyright in this code but I encourage its free use provided
+// that I don't carry any responsibility for the results. I am especially 
+// happy to see it used in free and open source software. If you do use 
+// it I would appreciate an acknowledgement of its origin in the code or
+// the product that results and I would also appreciate knowing a little
+// about the use to which it is being put. I am grateful to Frank Yellin
+// for some ideas that are used in this implementation.
+//
+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
+//
+// This is an implementation of the AES encryption algorithm (Rijndael)
+// designed by Joan Daemen and Vincent Rijmen. This version is designed
+// to provide both fixed and dynamic block and key lengths and can also 
+// run with either big or little endian internal byte order (see aes.h). 
+// It inputs block and key lengths in bytes with the legal values being 
+// 16, 24 and 32.
+
+/*
+ * Modified by Jari Ruusu,  May 1 2001
+ *  - Fixed some compile warnings, code was ok but gcc warned anyway.
+ *  - Changed basic types: byte -> unsigned char, word -> u_int32_t
+ *  - Major name space cleanup: Names visible to outside now begin
+ *    with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
+ *  - Removed C++ and DLL support as part of name space cleanup.
+ *  - Eliminated unnecessary recomputation of tables. (actual bug fix)
+ *  - Merged precomputed constant tables to aes.c file.
+ *  - Removed data alignment restrictions for portability reasons.
+ *  - Made block and key lengths accept bit count (128/192/256)
+ *    as well byte count (16/24/32).
+ *  - Removed all error checks. This change also eliminated the need
+ *    to preinitialize the context struct to zero.
+ *  - Removed some totally unused constants.
+ */
+
+#include "aes.h"
+
+// CONFIGURATION OPTIONS (see also aes.h)
+//
+// 1.  Define UNROLL for full loop unrolling in encryption and decryption.
+// 2.  Define PARTIAL_UNROLL to unroll two loops in encryption and decryption.
+// 3.  Define FIXED_TABLES for compiled rather than dynamic tables.
+// 4.  Define FF_TABLES to use tables for field multiplies and inverses.
+//     Do not enable this without understanding stack space requirements.
+// 5.  Define ARRAYS to use arrays to hold the local state block. If this
+//     is not defined, individually declared 32-bit words are used.
+// 6.  Define FAST_VARIABLE if a high speed variable block implementation
+//     is needed (essentially three separate fixed block size code sequences)
+// 7.  Define either ONE_TABLE or FOUR_TABLES for a fast table driven 
+//     version using 1 table (2 kbytes of table space) or 4 tables (8
+//     kbytes of table space) for higher speed.
+// 8.  Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed 
+//     increase by using tables for the last rounds but with more table
+//     space (2 or 8 kbytes extra).
+// 9.  If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but 
+//     slower version is provided.
+// 10. If fast decryption key scheduling is needed define ONE_IM_TABLE
+//     or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra).
+
+//#define UNROLL
+//#define PARTIAL_UNROLL
+
+//#define FIXED_TABLES
+//#define FF_TABLES
+#define ARRAYS
+#define FAST_VARIABLE
+
+//#define ONE_TABLE
+#define FOUR_TABLES
+
+//#define ONE_LR_TABLE
+#define FOUR_LR_TABLES
+
+//#define ONE_IM_TABLE
+#define FOUR_IM_TABLES
+
+#if defined(UNROLL) && defined (PARTIAL_UNROLL)
+#error both UNROLL and PARTIAL_UNROLL are defined
+#endif
+
+#if defined(ONE_TABLE) && defined (FOUR_TABLES)
+#error both ONE_TABLE and FOUR_TABLES are defined
+#endif
+
+#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES)
+#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined
+#endif
+
+#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES)
+#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined
+#endif
+
+#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32
+#error an illegal block size has been specified
+#endif  
+
+// upr(x,n): rotates bytes within words by n positions, moving bytes 
+// to higher index positions with wrap around into low positions
+// ups(x,n): moves bytes by n positions to higher index positions in 
+// words but without wrap around
+// bval(x,n): extracts a byte from a word
+
+#define upr(x,n)        (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n))))
+#define ups(x,n)        ((x) << 8 * (n))
+#define bval(x,n)       ((unsigned char)((x) >> 8 * (n)))
+#define bytes2word(b0, b1, b2, b3)  \
+        ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0))
+
+#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386)
+/* little endian processor without data alignment restrictions */
+#define word_in(x)      *(u_int32_t*)(x)
+#define word_out(x,v)   *(u_int32_t*)(x) = (v)
+#else
+/* slower but generic big endian or with data alignment restrictions */
+#define word_in(x)      ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24))
+#define word_out(x,v)   ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24)
+#endif
+
+// Disable at least some poor combinations of options
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+#define FIXED_TABLES
+#undef  UNROLL
+#undef  ONE_LR_TABLE
+#undef  FOUR_LR_TABLES
+#undef  ONE_IM_TABLE
+#undef  FOUR_IM_TABLES
+#elif !defined(FOUR_TABLES)
+#ifdef  FOUR_LR_TABLES
+#undef  FOUR_LR_TABLES
+#define ONE_LR_TABLE
+#endif
+#ifdef  FOUR_IM_TABLES
+#undef  FOUR_IM_TABLES
+#define ONE_IM_TABLE
+#endif
+#elif !defined(AES_BLOCK_SIZE)
+#if defined(UNROLL)
+#define PARTIAL_UNROLL
+#undef UNROLL
+#endif
+#endif
+
+// the finite field modular polynomial and elements
+
+#define ff_poly 0x011b
+#define ff_hi   0x80
+
+// multiply four bytes in GF(2^8) by 'x' {02} in parallel
+
+#define m1  0x80808080
+#define m2  0x7f7f7f7f
+#define m3  0x0000001b
+#define FFmulX(x)  ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3))
+
+// The following defines provide alternative definitions of FFmulX that might
+// give improved performance if a fast 32-bit multiply is not available. Note
+// that a temporary variable u needs to be defined where FFmulX is used.
+
+// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) 
+// #define m4  0x1b1b1b1b
+// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) 
+
+// perform column mix operation on four bytes in parallel
+
+#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1))
+
+#if defined(FIXED_TABLES)
+
+// the S-Box table
+
+static const unsigned char s_box[256] =
+{
+    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+    0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+    0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+    0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+    0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+    0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+    0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+    0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+    0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+    0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+    0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+    0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+    0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+    0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+    0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+    0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+    0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+    0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+    0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+    0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+    0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+    0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+    0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+    0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+    0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+    0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+    0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+// the inverse S-Box table
+
+static const unsigned char inv_s_box[256] =
+{
+    0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+    0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+    0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+    0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+    0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+    0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+    0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+    0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+    0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+    0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+    0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+    0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+    0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+    0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+    0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+    0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+    0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+    0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+    0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+    0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+    0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+    0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+    0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+    0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+    0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+    0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+    0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+    0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+    0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+    0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+    0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+    0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+#define w0(p)          0x000000##p
+
+// Number of elements required in this table for different
+// block and key lengths is:
+//
+// Nk =      4  6  8
+//        ----------
+// Nb = 4 | 10  8  7
+//      6 | 19 12 11
+//      8 | 29 19 14
+//
+// this table can be a table of bytes if the key schedule
+// code is adjusted accordingly
+
+static const u_int32_t rcon_tab[29] =
+{
+    w0(01), w0(02), w0(04), w0(08),
+    w0(10), w0(20), w0(40), w0(80),
+    w0(1b), w0(36), w0(6c), w0(d8),
+    w0(ab), w0(4d), w0(9a), w0(2f),
+    w0(5e), w0(bc), w0(63), w0(c6),
+    w0(97), w0(35), w0(6a), w0(d4),
+    w0(b3), w0(7d), w0(fa), w0(ef),
+    w0(c5)
+};
+
+#undef  w0
+
+#define r0(p,q,r,s) 0x##p##q##r##s
+#define r1(p,q,r,s) 0x##q##r##s##p
+#define r2(p,q,r,s) 0x##r##s##p##q
+#define r3(p,q,r,s) 0x##s##p##q##r
+#define w0(p)          0x000000##p
+#define w1(p)        0x0000##p##00
+#define w2(p)        0x00##p##0000
+#define w3(p)        0x##p##000000
+
+#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES)) 
+
+//  data for forward tables (other than last round)
+
+#define f_table \
+    r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\
+    r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\
+    r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\
+    r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\
+    r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\
+    r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\
+    r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\
+    r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\
+    r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\
+    r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\
+    r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\
+    r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\
+    r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\
+    r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\
+    r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\
+    r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\
+    r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\
+    r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\
+    r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\
+    r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\
+    r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\
+    r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\
+    r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\
+    r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\
+    r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\
+    r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\
+    r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\
+    r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\
+    r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\
+    r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\
+    r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\
+    r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\
+    r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\
+    r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\
+    r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\
+    r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\
+    r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\
+    r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\
+    r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\
+    r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\
+    r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\
+    r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\
+    r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\
+    r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\
+    r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\
+    r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\
+    r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\
+    r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\
+    r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\
+    r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\
+    r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\
+    r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\
+    r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\
+    r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\
+    r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\
+    r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\
+    r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\
+    r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\
+    r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\
+    r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\
+    r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\
+    r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\
+    r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\
+    r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c)
+
+//  data for inverse tables (other than last round)
+
+#define i_table \
+    r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\
+    r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\
+    r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\
+    r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\
+    r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\
+    r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\
+    r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\
+    r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\
+    r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\
+    r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\
+    r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\
+    r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\
+    r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\
+    r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\
+    r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\
+    r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\
+    r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\
+    r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\
+    r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\
+    r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\
+    r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\
+    r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\
+    r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\
+    r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\
+    r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\
+    r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\
+    r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\
+    r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\
+    r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\
+    r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\
+    r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\
+    r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\
+    r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\
+    r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\
+    r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\
+    r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\
+    r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\
+    r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\
+    r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\
+    r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\
+    r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\
+    r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\
+    r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\
+    r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\
+    r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\
+    r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\
+    r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\
+    r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\
+    r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\
+    r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\
+    r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\
+    r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\
+    r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\
+    r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\
+    r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\
+    r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\
+    r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\
+    r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\
+    r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\
+    r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\
+    r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\
+    r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\
+    r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\
+    r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0)
+
+// generate the required tables in the desired endian format
+
+#undef  r
+#define r   r0
+
+#if defined(ONE_TABLE)
+static const u_int32_t ft_tab[256] =
+    {   f_table };
+#elif defined(FOUR_TABLES)
+static const u_int32_t ft_tab[4][256] =
+{   {   f_table },
+#undef  r
+#define r   r1
+    {   f_table },
+#undef  r
+#define r   r2
+    {   f_table },
+#undef  r
+#define r   r3
+    {   f_table }
+};
+#endif
+
+#undef  r
+#define r   r0
+#if defined(ONE_TABLE)
+static const u_int32_t it_tab[256] =
+    {   i_table };
+#elif defined(FOUR_TABLES)
+static const u_int32_t it_tab[4][256] =
+{   {   i_table },
+#undef  r
+#define r   r1
+    {   i_table },
+#undef  r
+#define r   r2
+    {   i_table },
+#undef  r
+#define r   r3
+    {   i_table }
+};
+#endif
+
+#endif
+
+#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES)) 
+
+//  data for inverse tables (last round)
+
+#define li_table    \
+    w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\
+    w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\
+    w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\
+    w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\
+    w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\
+    w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\
+    w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\
+    w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\
+    w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\
+    w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\
+    w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\
+    w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\
+    w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\
+    w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\
+    w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\
+    w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\
+    w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\
+    w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\
+    w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\
+    w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\
+    w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\
+    w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\
+    w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\
+    w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\
+    w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\
+    w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\
+    w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\
+    w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\
+    w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\
+    w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\
+    w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\
+    w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d),
+
+// generate the required tables in the desired endian format
+
+#undef  r
+#define r(p,q,r,s)  w0(q)
+#if defined(ONE_LR_TABLE)
+static const u_int32_t fl_tab[256] =
+    {   f_table     };
+#elif defined(FOUR_LR_TABLES)
+static const u_int32_t fl_tab[4][256] =
+{   {   f_table    },
+#undef  r
+#define r(p,q,r,s)   w1(q)
+    {   f_table    },
+#undef  r
+#define r(p,q,r,s)   w2(q)
+    {   f_table    },
+#undef  r
+#define r(p,q,r,s)   w3(q)
+    {   f_table    }
+};
+#endif
+
+#undef  w
+#define w   w0
+#if defined(ONE_LR_TABLE)
+static const u_int32_t il_tab[256] =
+    {   li_table    };
+#elif defined(FOUR_LR_TABLES)
+static const u_int32_t il_tab[4][256] =
+{   {   li_table    },
+#undef  w
+#define w   w1
+    {   li_table    },
+#undef  w
+#define w   w2
+    {   li_table    },
+#undef  w
+#define w   w3
+    {   li_table    }
+};
+#endif
+
+#endif
+
+#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES)) 
+
+#define m_table \
+    r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\
+    r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\
+    r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\
+    r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\
+    r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\
+    r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\
+    r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\
+    r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\
+    r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\
+    r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\
+    r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\
+    r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\
+    r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\
+    r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\
+    r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\
+    r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\
+    r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\
+    r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\
+    r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\
+    r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\
+    r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\
+    r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\
+    r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\
+    r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\
+    r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\
+    r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\
+    r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\
+    r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\
+    r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\
+    r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\
+    r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\
+    r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\
+    r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\
+    r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\
+    r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\
+    r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\
+    r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\
+    r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\
+    r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\
+    r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\
+    r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\
+    r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\
+    r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\
+    r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\
+    r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\
+    r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\
+    r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\
+    r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\
+    r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\
+    r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\
+    r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\
+    r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\
+    r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\
+    r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\
+    r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\
+    r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\
+    r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\
+    r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\
+    r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\
+    r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\
+    r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\
+    r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\
+    r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\
+    r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d)
+
+#undef r
+#define r   r0
+
+#if defined(ONE_IM_TABLE)
+static const u_int32_t im_tab[256] =
+    {   m_table };
+#elif defined(FOUR_IM_TABLES)
+static const u_int32_t im_tab[4][256] =
+{   {   m_table },
+#undef  r
+#define r   r1
+    {   m_table },
+#undef  r
+#define r   r2
+    {   m_table },
+#undef  r
+#define r   r3
+    {   m_table }
+};
+#endif
+
+#endif
+
+#else
+
+static int tab_gen = 0;
+
+static unsigned char  s_box[256];            // the S box
+static unsigned char  inv_s_box[256];        // the inverse S box
+static u_int32_t  rcon_tab[AES_RC_LENGTH];   // table of round constants
+
+#if defined(ONE_TABLE)
+static u_int32_t  ft_tab[256];
+static u_int32_t  it_tab[256];
+#elif defined(FOUR_TABLES)
+static u_int32_t  ft_tab[4][256];
+static u_int32_t  it_tab[4][256];
+#endif
+
+#if defined(ONE_LR_TABLE)
+static u_int32_t  fl_tab[256];
+static u_int32_t  il_tab[256];
+#elif defined(FOUR_LR_TABLES)
+static u_int32_t  fl_tab[4][256];
+static u_int32_t  il_tab[4][256];
+#endif
+
+#if defined(ONE_IM_TABLE)
+static u_int32_t  im_tab[256];
+#elif defined(FOUR_IM_TABLES)
+static u_int32_t  im_tab[4][256];
+#endif
+
+// Generate the tables for the dynamic table option
+
+#if !defined(FF_TABLES)
+
+// It will generally be sensible to use tables to compute finite 
+// field multiplies and inverses but where memory is scarse this 
+// code might sometimes be better.
+
+// return 2 ^ (n - 1) where n is the bit number of the highest bit
+// set in x with x in the range 1 < x < 0x00000200.   This form is
+// used so that locals within FFinv can be bytes rather than words
+
+static unsigned char hibit(const u_int32_t x)
+{   unsigned char r = (unsigned char)((x >> 1) | (x >> 2));
+    
+    r |= (r >> 2);
+    r |= (r >> 4);
+    return (r + 1) >> 1;
+}
+
+// return the inverse of the finite field element x
+
+static unsigned char FFinv(const unsigned char x)
+{   unsigned char    p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+    if(x < 2) return x;
+
+    for(;;)
+    {
+        if(!n1) return v1;
+
+        while(n2 >= n1)
+        {   
+            n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
+        }
+        
+        if(!n2) return v2;
+
+        while(n1 >= n2)
+        {   
+            n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
+        }
+    }
+}
+
+// define the finite field multiplies required for Rijndael
+
+#define FFmul02(x)  ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0))
+#define FFmul03(x)  ((x) ^ FFmul02(x))
+#define FFmul09(x)  ((x) ^ FFmul02(FFmul02(FFmul02(x))))
+#define FFmul0b(x)  ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x))))
+#define FFmul0d(x)  ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x))))
+#define FFmul0e(x)  FFmul02((x) ^ FFmul02((x) ^ FFmul02(x)))
+
+#else
+
+#define FFinv(x)    ((x) ? pow[255 - log[x]]: 0)
+
+#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
+#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
+#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
+#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
+#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
+#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
+
+#endif
+
+// The forward and inverse affine transformations used in the S-box
+
+#define fwd_affine(x) \
+    (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8)))
+
+#define inv_affine(x) \
+    (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8)))
+
+static void gen_tabs(void)
+{   u_int32_t  i, w;
+
+#if defined(FF_TABLES)
+
+    unsigned char  pow[512], log[256];
+
+    // log and power tables for GF(2^8) finite field with
+    // 0x011b as modular polynomial - the simplest primitive
+    // root is 0x03, used here to generate the tables
+
+    i = 0; w = 1; 
+    do
+    {   
+        pow[i] = (unsigned char)w;
+        pow[i + 255] = (unsigned char)w;
+        log[w] = (unsigned char)i++;
+        w ^=  (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+    }
+    while (w != 1);
+
+#endif
+
+    for(i = 0, w = 1; i < AES_RC_LENGTH; ++i)
+    {
+        rcon_tab[i] = bytes2word(w, 0, 0, 0);
+        w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+    }
+
+    for(i = 0; i < 256; ++i)
+    {   unsigned char    b;
+
+        s_box[i] = b = fwd_affine(FFinv((unsigned char)i));
+
+        w = bytes2word(b, 0, 0, 0);
+#if defined(ONE_LR_TABLE)
+        fl_tab[i] = w;
+#elif defined(FOUR_LR_TABLES)
+        fl_tab[0][i] = w;
+        fl_tab[1][i] = upr(w,1);
+        fl_tab[2][i] = upr(w,2);
+        fl_tab[3][i] = upr(w,3);
+#endif
+        w = bytes2word(FFmul02(b), b, b, FFmul03(b));
+#if defined(ONE_TABLE)
+        ft_tab[i] = w;
+#elif defined(FOUR_TABLES)
+        ft_tab[0][i] = w;
+        ft_tab[1][i] = upr(w,1);
+        ft_tab[2][i] = upr(w,2);
+        ft_tab[3][i] = upr(w,3);
+#endif
+        inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i));
+
+        w = bytes2word(b, 0, 0, 0);
+#if defined(ONE_LR_TABLE)
+        il_tab[i] = w;
+#elif defined(FOUR_LR_TABLES)
+        il_tab[0][i] = w;
+        il_tab[1][i] = upr(w,1);
+        il_tab[2][i] = upr(w,2);
+        il_tab[3][i] = upr(w,3);
+#endif
+        w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b));
+#if defined(ONE_TABLE)
+        it_tab[i] = w;
+#elif defined(FOUR_TABLES)
+        it_tab[0][i] = w;
+        it_tab[1][i] = upr(w,1);
+        it_tab[2][i] = upr(w,2);
+        it_tab[3][i] = upr(w,3);
+#endif
+#if defined(ONE_IM_TABLE)
+        im_tab[b] = w;
+#elif defined(FOUR_IM_TABLES)
+        im_tab[0][b] = w;
+        im_tab[1][b] = upr(w,1);
+        im_tab[2][b] = upr(w,2);
+        im_tab[3][b] = upr(w,3);
+#endif
+
+    }
+}
+
+#endif
+
+#define no_table(x,box,vf,rf,c) bytes2word( \
+    box[bval(vf(x,0,c),rf(0,c))], \
+    box[bval(vf(x,1,c),rf(1,c))], \
+    box[bval(vf(x,2,c),rf(2,c))], \
+    box[bval(vf(x,3,c),rf(3,c))])
+
+#define one_table(x,op,tab,vf,rf,c) \
+ (     tab[bval(vf(x,0,c),rf(0,c))] \
+  ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
+  ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
+  ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
+
+#define four_tables(x,tab,vf,rf,c) \
+ (  tab[0][bval(vf(x,0,c),rf(0,c))] \
+  ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
+  ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
+  ^ tab[3][bval(vf(x,3,c),rf(3,c))])
+
+#define vf1(x,r,c)  (x)
+#define rf1(r,c)    (r)
+#define rf2(r,c)    ((r-c)&3)
+
+#if defined(FOUR_LR_TABLES)
+#define ls_box(x,c)     four_tables(x,fl_tab,vf1,rf2,c)
+#elif defined(ONE_LR_TABLE)
+#define ls_box(x,c)     one_table(x,upr,fl_tab,vf1,rf2,c)
+#else
+#define ls_box(x,c)     no_table(x,s_box,vf1,rf2,c)
+#endif
+
+#if defined(FOUR_IM_TABLES)
+#define inv_mcol(x)     four_tables(x,im_tab,vf1,rf1,0)
+#elif defined(ONE_IM_TABLE)
+#define inv_mcol(x)     one_table(x,upr,im_tab,vf1,rf1,0)
+#else
+#define inv_mcol(x) \
+    (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \
+    f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1))
+#endif
+
+// Subroutine to set the block size (if variable) in bytes, legal
+// values being 16, 24 and 32.
+
+#if defined(AES_BLOCK_SIZE)
+#define nc   (AES_BLOCK_SIZE / 4)
+#else
+#define nc   (cx->aes_Ncol)
+
+void aes_set_blk(aes_context *cx, int n_bytes)
+{
+#if !defined(FIXED_TABLES)
+    if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+#endif
+
+    switch(n_bytes) {
+    case 32:        /* bytes */
+    case 256:       /* bits */
+        nc = 8;
+        break;
+    case 24:        /* bytes */
+    case 192:       /* bits */
+        nc = 6;
+        break;
+    case 16:        /* bytes */
+    case 128:       /* bits */
+    default:
+        nc = 4;
+        break;
+    }
+}
+
+#endif
+
+// Initialise the key schedule from the user supplied key. The key
+// length is now specified in bytes - 16, 24 or 32 as appropriate.
+// This corresponds to bit lengths of 128, 192 and 256 bits, and
+// to Nk values of 4, 6 and 8 respectively.
+
+#define mx(t,f) (*t++ = inv_mcol(*f),f++)
+#define cp(t,f) *t++ = *f++
+
+#if   AES_BLOCK_SIZE == 16
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#elif AES_BLOCK_SIZE == 24
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+                    cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+                    mx(d,s); mx(d,s)
+#elif AES_BLOCK_SIZE == 32
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+                    cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+                    mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#else
+
+#define cpy(d,s) \
+switch(nc) \
+{   case 8: cp(d,s); cp(d,s); \
+    case 6: cp(d,s); cp(d,s); \
+    case 4: cp(d,s); cp(d,s); \
+            cp(d,s); cp(d,s); \
+}
+
+#define mix(d,s) \
+switch(nc) \
+{   case 8: mx(d,s); mx(d,s); \
+    case 6: mx(d,s); mx(d,s); \
+    case 4: mx(d,s); mx(d,s); \
+            mx(d,s); mx(d,s); \
+}
+
+#endif
+
+void aes_set_key(aes_context *cx, const unsigned char in_key[], int n_bytes, const int f)
+{   u_int32_t    *kf, *kt, rci;
+
+#if !defined(FIXED_TABLES)
+    if(!tab_gen) { gen_tabs(); tab_gen = 1; }
+#endif
+
+    switch(n_bytes) {
+    case 32:                    /* bytes */
+    case 256:                   /* bits */
+        cx->aes_Nkey = 8;
+        break;
+    case 24:                    /* bytes */
+    case 192:                   /* bits */
+        cx->aes_Nkey = 6;
+        break;
+    case 16:                    /* bytes */
+    case 128:                   /* bits */
+    default:
+        cx->aes_Nkey = 4;
+        break;
+    }
+
+    cx->aes_Nrnd = (cx->aes_Nkey > nc ? cx->aes_Nkey : nc) + 6; 
+
+    cx->aes_e_key[0] = word_in(in_key     );
+    cx->aes_e_key[1] = word_in(in_key +  4);
+    cx->aes_e_key[2] = word_in(in_key +  8);
+    cx->aes_e_key[3] = word_in(in_key + 12);
+
+    kf = cx->aes_e_key; 
+    kt = kf + nc * (cx->aes_Nrnd + 1) - cx->aes_Nkey; 
+    rci = 0;
+
+    switch(cx->aes_Nkey)
+    {
+    case 4: do
+            {   kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++];
+                kf[5] = kf[1] ^ kf[4];
+                kf[6] = kf[2] ^ kf[5];
+                kf[7] = kf[3] ^ kf[6];
+                kf += 4;
+            }
+            while(kf < kt);
+            break;
+
+    case 6: cx->aes_e_key[4] = word_in(in_key + 16);
+            cx->aes_e_key[5] = word_in(in_key + 20);
+            do
+            {   kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++];
+                kf[ 7] = kf[1] ^ kf[ 6];
+                kf[ 8] = kf[2] ^ kf[ 7];
+                kf[ 9] = kf[3] ^ kf[ 8];
+                kf[10] = kf[4] ^ kf[ 9];
+                kf[11] = kf[5] ^ kf[10];
+                kf += 6;
+            }
+            while(kf < kt);
+            break;
+
+    case 8: cx->aes_e_key[4] = word_in(in_key + 16);
+            cx->aes_e_key[5] = word_in(in_key + 20);
+            cx->aes_e_key[6] = word_in(in_key + 24);
+            cx->aes_e_key[7] = word_in(in_key + 28);
+            do
+            {   kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++];
+                kf[ 9] = kf[1] ^ kf[ 8];
+                kf[10] = kf[2] ^ kf[ 9];
+                kf[11] = kf[3] ^ kf[10];
+                kf[12] = kf[4] ^ ls_box(kf[11],0);
+                kf[13] = kf[5] ^ kf[12];
+                kf[14] = kf[6] ^ kf[13];
+                kf[15] = kf[7] ^ kf[14];
+                kf += 8;
+            }
+            while (kf < kt);
+            break;
+    }
+
+    if(!f)
+    {   u_int32_t    i;
+        
+        kt = cx->aes_d_key + nc * cx->aes_Nrnd;
+        kf = cx->aes_e_key;
+        
+        cpy(kt, kf); kt -= 2 * nc;
+
+        for(i = 1; i < cx->aes_Nrnd; ++i)
+        { 
+#if defined(ONE_TABLE) || defined(FOUR_TABLES)
+#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES)
+            u_int32_t    f2, f4, f8, f9;
+#endif
+            mix(kt, kf);
+#else
+            cpy(kt, kf);
+#endif
+            kt -= 2 * nc;
+        }
+        
+        cpy(kt, kf);
+    }
+}
+
+// y = output word, x = input word, r = row, c = column
+// for r = 0, 1, 2 and 3 = column accessed for row r
+
+#if defined(ARRAYS)
+#define s(x,c) x[c]
+#else
+#define s(x,c) x##c
+#endif
+
+// I am grateful to Frank Yellin for the following constructions
+// which, given the column (c) of the output state variable that
+// is being computed, return the input state variables which are
+// needed for each row (r) of the state
+
+// For the fixed block size options, compilers reduce these two 
+// expressions to fixed variable references. For variable block 
+// size code conditional clauses will sometimes be returned
+
+#define unused  77  // Sunset Strip
+
+#define fwd_var(x,r,c) \
+ ( r==0 ?			\
+    ( c==0 ? s(x,0) \
+    : c==1 ? s(x,1) \
+    : c==2 ? s(x,2) \
+    : c==3 ? s(x,3) \
+    : c==4 ? s(x,4) \
+    : c==5 ? s(x,5) \
+    : c==6 ? s(x,6) \
+    : s(x,7))		\
+ : r==1 ?			\
+    ( c==0 ? s(x,1) \
+    : c==1 ? s(x,2) \
+    : c==2 ? s(x,3) \
+    : c==3 ? nc==4 ? s(x,0) : s(x,4) \
+    : c==4 ? s(x,5) \
+    : c==5 ? nc==8 ? s(x,6) : s(x,0) \
+    : c==6 ? s(x,7) \
+    : s(x,0))		\
+ : r==2 ?			\
+    ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
+    : c==1 ? nc==8 ? s(x,4) : s(x,3) \
+    : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+    : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+    : c==4 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==5 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==6 ? s(x,1) \
+    : s(x,2))		\
+ :					\
+    ( c==0 ? nc==8 ? s(x,4) : s(x,3) \
+    : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+    : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+    : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \
+    : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==6 ? s(x,2) \
+    : s(x,3)))
+
+#define inv_var(x,r,c) \
+ ( r==0 ?			\
+    ( c==0 ? s(x,0) \
+    : c==1 ? s(x,1) \
+    : c==2 ? s(x,2) \
+    : c==3 ? s(x,3) \
+    : c==4 ? s(x,4) \
+    : c==5 ? s(x,5) \
+    : c==6 ? s(x,6) \
+    : s(x,7))		\
+ : r==1 ?			\
+    ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \
+    : c==1 ? s(x,0) \
+    : c==2 ? s(x,1) \
+    : c==3 ? s(x,2) \
+    : c==4 ? s(x,3) \
+    : c==5 ? s(x,4) \
+    : c==6 ? s(x,5) \
+    : s(x,6))		\
+ : r==2 ?			\
+    ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+    : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+    : c==2 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==3 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==4 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==5 ? nc==8 ? s(x,2) : s(x,3) \
+    : c==6 ? s(x,3) \
+    : s(x,4))		\
+ :					\
+    ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \
+    : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+    : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+    : c==3 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==6 ? s(x,2) \
+    : s(x,3)))
+
+#define si(y,x,k,c) s(y,c) = word_in(x + 4 * c) ^ k[c]
+#define so(y,x,c)   word_out(y + 4 * c, s(x,c))
+
+#if defined(FOUR_TABLES)
+#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
+#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
+#elif defined(ONE_TABLE)
+#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
+#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
+#else
+#define fwd_rnd(y,x,k,c)    s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
+#define inv_rnd(y,x,k,c)    s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
+#endif
+
+#if defined(FOUR_LR_TABLES)
+#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
+#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
+#elif defined(ONE_LR_TABLE)
+#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
+#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
+#else
+#define fwd_lrnd(y,x,k,c)   s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
+#define inv_lrnd(y,x,k,c)   s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
+#endif
+
+#if AES_BLOCK_SIZE == 16
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[4],y[4]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+// the following defines prevent the compiler requiring the declaration
+// of generated but unused variables in the fwd_var and inv_var macros
+#define b04 unused
+#define b05 unused
+#define b06 unused
+#define b07 unused
+#define b14 unused
+#define b15 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#elif AES_BLOCK_SIZE == 24
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[6],y[6]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5, \
+                        y##0,y##1,y##2,y##3,y##4,y##5
+#define b06 unused
+#define b07 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
+                        si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); \
+                        so(y,x,3); so(y,x,4); so(y,x,5)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
+                        rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
+#else
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[8],y[8]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
+                        y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5); \
+                        s(y,6) = s(x,6); s(y,7) = s(x,7);
+
+#if AES_BLOCK_SIZE == 32
+
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
+                        si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
+                        so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
+                        rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
+#else
+
+#define state_in(y,x,k) \
+switch(nc) \
+{   case 8: si(y,x,k,7); si(y,x,k,6); \
+    case 6: si(y,x,k,5); si(y,x,k,4); \
+    case 4: si(y,x,k,3); si(y,x,k,2); \
+            si(y,x,k,1); si(y,x,k,0); \
+}
+
+#define state_out(y,x) \
+switch(nc) \
+{   case 8: so(y,x,7); so(y,x,6); \
+    case 6: so(y,x,5); so(y,x,4); \
+    case 4: so(y,x,3); so(y,x,2); \
+            so(y,x,1); so(y,x,0); \
+}
+
+#if defined(FAST_VARIABLE)
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
+            rm(y,x,k,5); rm(y,x,k,4); \
+            rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+    case 6: rm(y,x,k,5); rm(y,x,k,4); \
+            rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+    case 4: rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+}
+#else
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
+    case 6: rm(y,x,k,5); rm(y,x,k,4); \
+    case 4: rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+}
+
+#endif
+
+#endif
+#endif
+
+void aes_encrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+{   u_int32_t        locals(b0, b1);
+    const u_int32_t  *kp = cx->aes_e_key;
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+    u_int32_t        f2;
+#endif
+
+    state_in(b0, in_blk, kp); kp += nc;
+
+#if defined(UNROLL)
+
+    switch(cx->aes_Nrnd)
+    {
+    case 14:    round(fwd_rnd,  b1, b0, kp         ); 
+                round(fwd_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
+    case 12:    round(fwd_rnd,  b1, b0, kp         ); 
+                round(fwd_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
+    case 10:    round(fwd_rnd,  b1, b0, kp         );             
+                round(fwd_rnd,  b0, b1, kp +     nc);
+                round(fwd_rnd,  b1, b0, kp + 2 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 3 * nc);
+                round(fwd_rnd,  b1, b0, kp + 4 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 5 * nc);
+                round(fwd_rnd,  b1, b0, kp + 6 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 7 * nc);
+                round(fwd_rnd,  b1, b0, kp + 8 * nc);
+                round(fwd_lrnd, b0, b1, kp + 9 * nc);
+    }
+
+#elif defined(PARTIAL_UNROLL)
+    {   u_int32_t    rnd;
+
+        for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
+        {
+            round(fwd_rnd, b1, b0, kp); 
+            round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc;
+        }
+
+        round(fwd_rnd,  b1, b0, kp);
+        round(fwd_lrnd, b0, b1, kp + nc);
+    }
+#else
+    {   u_int32_t    rnd;
+
+        for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
+        {
+            round(fwd_rnd, b1, b0, kp); 
+            l_copy(b0, b1); kp += nc;
+        }
+
+        round(fwd_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out_blk, b0);
+}
+
+void aes_decrypt(const aes_context *cx, const unsigned char in_blk[], unsigned char out_blk[])
+{   u_int32_t        locals(b0, b1);
+    const u_int32_t  *kp = cx->aes_d_key;
+
+#if !defined(ONE_TABLE) && !defined(FOUR_TABLES)
+    u_int32_t        f2, f4, f8, f9; 
+#endif
+
+    state_in(b0, in_blk, kp); kp += nc;
+
+#if defined(UNROLL)
+
+    switch(cx->aes_Nrnd)
+    {
+    case 14:    round(inv_rnd,  b1, b0, kp         );
+                round(inv_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
+    case 12:    round(inv_rnd,  b1, b0, kp         );
+                round(inv_rnd,  b0, b1, kp + nc    ); kp += 2 * nc;
+    case 10:    round(inv_rnd,  b1, b0, kp         );             
+                round(inv_rnd,  b0, b1, kp +     nc);
+                round(inv_rnd,  b1, b0, kp + 2 * nc); 
+                round(inv_rnd,  b0, b1, kp + 3 * nc);
+                round(inv_rnd,  b1, b0, kp + 4 * nc); 
+                round(inv_rnd,  b0, b1, kp + 5 * nc);
+                round(inv_rnd,  b1, b0, kp + 6 * nc); 
+                round(inv_rnd,  b0, b1, kp + 7 * nc);
+                round(inv_rnd,  b1, b0, kp + 8 * nc);
+                round(inv_lrnd, b0, b1, kp + 9 * nc);
+    }
+
+#elif defined(PARTIAL_UNROLL)
+    {   u_int32_t    rnd;
+
+        for(rnd = 0; rnd < (cx->aes_Nrnd >> 1) - 1; ++rnd)
+        {
+            round(inv_rnd, b1, b0, kp); 
+            round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc;
+        }
+
+        round(inv_rnd,  b1, b0, kp);
+        round(inv_lrnd, b0, b1, kp + nc);
+    }
+#else
+    {   u_int32_t    rnd;
+
+        for(rnd = 0; rnd < cx->aes_Nrnd - 1; ++rnd)
+        {
+            round(inv_rnd, b1, b0, kp); 
+            l_copy(b0, b1); kp += nc;
+        }
+
+        round(inv_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out_blk, b0);
+}
diff -ru --new-file util-linux-2.11y/mount/aes.h util-linux-AES/mount/aes.h
--- util-linux-2.11y/mount/aes.h	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/aes.h	Thu Feb  6 23:22:05 2003
@@ -0,0 +1,97 @@
+// I retain copyright in this code but I encourage its free use provided
+// that I don't carry any responsibility for the results. I am especially 
+// happy to see it used in free and open source software. If you do use 
+// it I would appreciate an acknowledgement of its origin in the code or
+// the product that results and I would also appreciate knowing a little
+// about the use to which it is being put. I am grateful to Frank Yellin
+// for some ideas that are used in this implementation.
+//
+// Dr B. R. Gladman <brg@gladman.uk.net> 6th April 2001.
+//
+// This is an implementation of the AES encryption algorithm (Rijndael)
+// designed by Joan Daemen and Vincent Rijmen. This version is designed
+// to provide both fixed and dynamic block and key lengths and can also 
+// run with either big or little endian internal byte order (see aes.h). 
+// It inputs block and key lengths in bytes with the legal values being 
+// 16, 24 and 32.
+
+/*
+ * Modified by Jari Ruusu,  May 1 2001
+ *  - Fixed some compile warnings, code was ok but gcc warned anyway.
+ *  - Changed basic types: byte -> unsigned char, word -> u_int32_t
+ *  - Major name space cleanup: Names visible to outside now begin
+ *    with "aes_" or "AES_". A lot of stuff moved from aes.h to aes.c
+ *  - Removed C++ and DLL support as part of name space cleanup.
+ *  - Eliminated unnecessary recomputation of tables. (actual bug fix)
+ *  - Merged precomputed constant tables to aes.c file.
+ *  - Removed data alignment restrictions for portability reasons.
+ *  - Made block and key lengths accept bit count (128/192/256)
+ *    as well byte count (16/24/32).
+ *  - Removed all error checks. This change also eliminated the need
+ *    to preinitialize the context struct to zero.
+ *  - Removed some totally unused constants.
+ */
+
+#ifndef _AES_H
+#define _AES_H
+
+#if defined(__linux__) && defined(__KERNEL__)
+#  include <linux/types.h>
+#else 
+#  include <sys/types.h>
+#endif
+
+// CONFIGURATION OPTIONS (see also aes.c)
+//
+// Define AES_BLOCK_SIZE to set the cipher block size (16, 24 or 32) or
+// leave this undefined for dynamically variable block size (this will
+// result in much slower code).
+// IMPORTANT NOTE: AES_BLOCK_SIZE is in BYTES (16, 24, 32 or undefined). If
+// left undefined a slower version providing variable block length is compiled
+
+#define AES_BLOCK_SIZE  16
+
+// The number of key schedule words for different block and key lengths
+// allowing for method of computation which requires the length to be a
+// multiple of the key length
+//
+// Nk =       4   6   8
+//        -------------
+// Nb = 4 |  60  60  64
+//      6 |  96  90  96
+//      8 | 120 120 120
+
+#if !defined(AES_BLOCK_SIZE) || (AES_BLOCK_SIZE == 32)
+#define AES_KS_LENGTH   120
+#define AES_RC_LENGTH    29
+#else
+#define AES_KS_LENGTH   4 * AES_BLOCK_SIZE
+#define AES_RC_LENGTH   (9 * AES_BLOCK_SIZE) / 8 - 8
+#endif
+
+typedef struct
+{
+    u_int32_t    aes_Nkey;      // the number of words in the key input block
+    u_int32_t    aes_Nrnd;      // the number of cipher rounds
+    u_int32_t    aes_e_key[AES_KS_LENGTH];   // the encryption key schedule
+    u_int32_t    aes_d_key[AES_KS_LENGTH];   // the decryption key schedule
+#if !defined(AES_BLOCK_SIZE)
+    u_int32_t    aes_Ncol;      // the number of columns in the cipher state
+#endif
+} aes_context;
+
+// THE CIPHER INTERFACE
+
+#if !defined(AES_BLOCK_SIZE)
+extern void aes_set_blk(aes_context *, const int);
+#endif
+extern void aes_set_key(aes_context *, const unsigned char [], const int, const int);
+extern void aes_encrypt(const aes_context *, const unsigned char [], unsigned char []);
+extern void aes_decrypt(const aes_context *, const unsigned char [], unsigned char []);
+
+// The block length inputs to aes_set_block and aes_set_key are in numbers
+// of bytes or bits.  The calls to subroutines must be made in the above
+// order but multiple calls can be made without repeating earlier calls
+// if their parameters have not changed.
+
+#endif  // _AES_H
diff -ru --new-file util-linux-2.11y/mount/lomount.c util-linux-AES/mount/lomount.c
--- util-linux-2.11y/mount/lomount.c	Fri Nov  1 02:58:51 2002
+++ util-linux-AES/mount/lomount.c	Wed Feb 12 17:06:01 2003
@@ -6,6 +6,16 @@
  * - added Native Language Support
  * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixed strerr(errno) in gettext calls
+ * 2000-09-24 Marc Mutz <Marc@Mutz.com>
+ * - added long option names and the --pass-fd option to pass
+ *   passphrases via fd's to losetup/mount. Used for encryption in
+ *   non-interactive environments. The idea behind xgetpass() is stolen
+ *   from GnuPG, v.1.0.3 (http://www.gnupg.org/).
+ * 2003-03-07 Fruhwirth Clemens <clemens@endorphin.org>
+ * - added/merged crypto support for:
+ *	- loop-AES (from Jari Ruusu <jari.ruusu@pp.inet.fi>)
+ *	- cryptoloop for 2.4.x (from kerneli.org <cryptoapi-devel@kerneli.org>)
+ * 	- cryptoloop for 2.5.x (from Fruhwirth Clemens <clemens@endorphin.org>)
  */
 
 #define PROC_DEVICES	"/proc/devices"
@@ -21,55 +31,128 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <limits.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/sysmacros.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <locale.h>
 
 #include "loop.h"
 #include "lomount.h"
+#include "rmd160.h"
+#include "sha512.h"
+#include "aes.h"
 #include "xstrncpy.h"
 #include "nls.h"
 
+#ifndef LO_CRYPT_CRYPTOAPI
+#define LO_CRYPT_CRYPTOAPI 18
+#endif
+#ifndef LO_CRYPT_NONE
+#define LO_CRYPT_NONE 0
+#endif
+#ifndef LO_CRYPT_XOR
+#define LO_CRYPT_XOR 1
+#endif
+#ifndef LO_CRYPT_DES
+#define LO_CRYPT_DES 2
+#endif
+#ifndef LO_CRYPT_FISH2
+#define LO_CRYPT_FISH2 3
+#endif
+#ifndef LO_CRYPT_BLOW
+#define LO_CRYPT_BLOW 4
+#endif
+#ifndef LO_CRYPT_CAST128
+#define LO_CRYPT_CAST128 5
+#endif
+#ifndef LO_CRYPT_IDEA
+#define LO_CRYPT_IDEA 6
+#endif
+#ifndef LO_CRYPT_SERPENT
+#define LO_CRYPT_SERPENT 7
+#endif
+#ifndef LO_CRYPT_MARS
+#define LO_CRYPT_MARS 8
+#endif
+#ifndef LO_CRYPT_RC6
+#define LO_CRYPT_RC6 11
+#endif
+#ifndef LO_CRYPT_3DES
+#define LO_CRYPT_3DES 12
+#endif
+#ifndef LO_CRYPT_DFC
+#define LO_CRYPT_DFC 15
+#endif
+#ifndef LO_CRYPT_RIJNDAEL
+#define LO_CRYPT_RIJNDAEL 16
+#endif
+
+#if !defined(LOOP_PASSWORD_MIN_LENGTH)
+# define  LOOP_PASSWORD_MIN_LENGTH   20
+#endif
+
+
 extern int verbose;
 extern char *xstrdup (const char *s);	/* not: #include "sundries.h" */
 extern void error (const char *fmt, ...);	/* idem */
+extern void show_all_loops(void);
+extern int read_options_from_fstab(char *, char **, char **, char **, char **, char **,
+			    char **, char **, char **, char **);
+
+// CryptoAPI cipher struct
+
+struct cipher_info
+{
+	const char *name;
+	int blocksize;
+	int keysize_mask;
+	int ivsize;
+	int key_schedule_size;
+};
+
+static int set_loop_passwd(struct loop_info *_loopinfo, int pfd, int keysz,
+			   const char *phash_name, const char *encryption, 
+			   int fd, int ffd, char *passIterThousands, char *gpgHomeDir,
+			   char *gpgKeyFile, int passAskTwice, char *loInitValue,
+			   char *passSeedString);
+static int get_cipher_info(const char *name, struct cipher_info *res);
+static int name_to_id(const char *name);
+#ifdef MAIN
+static char *id_to_name(int id);
+#endif
+ 
 
 #ifdef LOOP_SET_FD
 struct crypt_type_struct {
 	int id;
 	char *name;
+	int keylength;
 } crypt_type_tbl[] = {
-	{ LO_CRYPT_NONE, "no" },
-	{ LO_CRYPT_NONE, "none" },
-	{ LO_CRYPT_XOR, "xor" },
-	{ LO_CRYPT_DES, "DES" },
-	{ -1, NULL   }
+        { LO_CRYPT_NONE, "none", 0 },
+        { LO_CRYPT_NONE, "no", 0 },
+        { LO_CRYPT_XOR, "xor", 0 },
+        { LO_CRYPT_DES, "des", 8 },
+        { LO_CRYPT_FISH2, "twofish", 20 },
+        { LO_CRYPT_BLOW, "blowfish", 20 },
+        { LO_CRYPT_CAST128, "cast", 16 },
+        { LO_CRYPT_SERPENT, "serpent", 16 },
+        { LO_CRYPT_MARS, "mars", 16 },
+        { LO_CRYPT_RC6, "rc6", 16 },
+        { LO_CRYPT_3DES, "des-ede3", 24 },
+        { LO_CRYPT_DFC, "dfc", 16 },
+        { LO_CRYPT_IDEA, "idea", 16 },
+        { LO_CRYPT_RIJNDAEL, "rijndael", 16 },
+	{ -1, NULL,0   }
 };
 
-static int 
-crypt_type (const char *name) {
-	int i;
-
-	if (name) {
-		for (i = 0; crypt_type_tbl[i].id != -1; i++)
-			if (!strcasecmp (name, crypt_type_tbl[i].name))
-				return crypt_type_tbl[i].id;
-	}
-	return -1;
-}
-
 #ifdef MAIN
-static char *
-crypt_name (int id) {
-	int i;
-
-	for (i = 0; crypt_type_tbl[i].id != -1; i++)
-		if (id == crypt_type_tbl[i].id)
-			return crypt_type_tbl[i].name;
-	return "undefined";
-}
-
 static int
 show_loop (char *device) {
 	struct loop_info loopinfo;
@@ -91,40 +174,13 @@
 	printf (_("%s: [%04x]:%ld (%s) offset %d, %s encryption\n"),
 		device, loopinfo.lo_device, loopinfo.lo_inode,
 		loopinfo.lo_name, loopinfo.lo_offset,
-		crypt_name (loopinfo.lo_encrypt_type));
+		id_to_name(loopinfo.lo_encrypt_type));
 	close (fd);
 
 	return 0;
 }
 #endif
 
-int
-is_loop_device (const char *device) {
-	struct stat statbuf;
-	int loopmajor;
-#if 1
-	loopmajor = 7;
-#else
-	FILE *procdev;
-	char line[100], *cp;
-
-	loopmajor = 0;
-	if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
-		while (fgets (line, sizeof(line), procdev)) {
-			if ((cp = strstr (line, " loop\n")) != NULL) {
-				*cp='\0';
-				loopmajor=atoi(line);
-				break;
-			}
-		}
-		fclose(procdev);
-	}
-#endif
-	return (loopmajor && stat(device, &statbuf) == 0 &&
-		S_ISBLK(statbuf.st_mode) &&
-		major(statbuf.st_rdev) == loopmajor);
-}
-
 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
 
 char *
@@ -184,24 +240,262 @@
 		error(_(
 		    "mount: Could not find any loop device, and, according to %s,\n"
 		    "       this kernel does not know about the loop device.\n"
-		    "       (If so, then recompile or `insmod loop.o'.)"),
+		    "       (If so, then recompile or `modprobe loop'.)"),
 		      PROC_DEVICES);
 	    else
 		error(_(
 		    "mount: Could not find any loop device. Maybe this kernel does not know\n"
-		    "       about the loop device (then recompile or `insmod loop.o'), or\n"
+		    "       about the loop device (then recompile or `modprobe loop'), or\n"
 		    "       maybe /dev/loop# has the wrong major number?"));
 	} else
 		error(_("mount: could not find any free loop device"));
 	return 0;
 }
 
+static int rd_wr_retry(int fd, char *buf, int cnt, int w)
+{
+ 	int x, y, z;
+
+	x = 0;
+	while(x < cnt) {
+	        y = cnt - x;
+	        if(w) {
+	                z = write(fd, buf + x, y);
+	        } else {
+	                z = read(fd, buf + x, y);
+	                if (!z) return x;
+	        }
+	        if(z < 0) {
+	                if ((errno == EAGAIN) || (errno == ENOMEM) || (errno == ERESTART) || (errno == EINTR)) {
+	                        continue;
+	                }
+	                return x;
+	        }
+	        x += z;
+	}
+	return x;
+}
+ 
+static char *get_FD_pass(int fd)
+{
+ 	char *p = NULL;
+ 	int x = 0, y = 0;
+
+	do {
+	    	if(y >= (x - 1)) {
+	    	        x += 128; 
+	    	        if(!(p = realloc(p, x))) break;
+	    	}
+	    	if(rd_wr_retry(fd, p + y, 1, 0) != 1) break;
+	    	if((p[y] == '\n') || !p[y]) break;
+	    	y++;
+	} while(1); 
+	if(p) p[y] = 0;
+	return p;
+}
+
+static char *do_GPG_pipe(char *pass, char *gpgHomeDir, char *gpgKeyFile)
+{
+ 	int	x, pfdi[2], pfdo[2];
+ 	char	str[10], *a[16], *e[2], *h;
+ 	pid_t   gpid;
+ 	struct passwd *p;
+
+	if((getuid() == 0) && gpgHomeDir && gpgHomeDir[0]) {
+	        h = gpgHomeDir;
+	} else {
+	        if(!(p = getpwuid(getuid()))) {
+	                nomem1:
+	                fprintf(stderr, _("Error: Unable to allocate memory\n"));
+	                return NULL;
+	        }
+	        h = p->pw_dir;
+	}
+	if(!(e[0] = malloc(strlen(h) + 6))) goto nomem1;
+	sprintf(e[0], "HOME=%s", h);
+	e[1] = 0;
+
+	if(pipe(&pfdi[0])) {
+	        nomem2:
+	        free(e[0]);
+	        goto nomem1;
+	}
+	if(pipe(&pfdo[0])) {
+	        close(pfdi[0]);
+	        close(pfdi[1]);
+	        goto nomem2;   
+	}
+
+	/*
+	 * When this code is run as part of losetup, normal read permissions
+	 * affect the open() below because losetup is not setuid-root.
+	 *
+	 * When this code is run as part of mount, only root can set
+	 * 'gpgKeyFile' and as such, only root can decide what file is opened
+	 * below. However, since mount is usually setuid-root all non-root   
+	 * users can also open() the file too, but that file's contents are  
+	 * only piped to gpg. This readable-for-all is intended behaviour,   
+	 * and is very useful in situations where non-root users mount loop  
+	 * devices with their own gpg private key, and yet don't have access 
+	 * to the actual key used to encrypt loop device.
+	 */
+	if((x = open(gpgKeyFile, O_RDONLY)) == -1) {
+	        fprintf(stderr, _("Error: unable to open %s for reading\n"), gpgKeyFile);
+	        free(e[0]);
+	        close(pfdo[0]);
+	        close(pfdo[1]);
+	        close(pfdi[0]);
+ 	        close(pfdi[1]);
+	        return NULL;   
+	}
+
+	sprintf(str, "%d", pfdi[0]);
+	if(!(gpid = fork())) {
+	        dup2(x, 0);   
+	        dup2(pfdo[1], 1);
+	        close(x);
+	        close(pfdi[1]);
+	        close(pfdo[0]);
+	        close(pfdo[1]);
+	        if((x = open("/dev/null", O_WRONLY)) >= 0) {
+	                dup2(x, 2);
+	                close(x);  
+	        }
+	        x = 0;
+	        a[x++] = "gpg";
+	        if(gpgHomeDir && gpgHomeDir[0]) {
+	                a[x++] = "--homedir";
+	                a[x++] = gpgHomeDir; 
+	        }
+	        a[x++] = "--options";
+	        a[x++] = "/dev/null";
+	        a[x++] = "--quiet";  
+	 	a[x++] = "--batch";  
+		a[x++] = "--no-tty"; 
+	  	a[x++] = "--passphrase-fd";
+	        a[x++] = str;
+	        a[x++] = "--decrypt";
+	  	a[x] = 0;
+	        if(getuid() != geteuid())
+	                setuid(getuid());
+	        execve("/bin/gpg", &a[0], &e[0]);
+	        execve("/usr/bin/gpg", &a[0], &e[0]);
+	        execve("/usr/local/bin/gpg", &a[0], &e[0]);
+	        exit(1);
+	}
+	free(e[0]);
+	close(x);  
+	close(pfdi[0]);
+	close(pfdo[1]);
+	if(gpid == -1) {
+	        close(pfdi[1]);
+	        close(pfdo[0]);
+	        goto nomem1;   
+	}
+
+	x = strlen(pass);
+	rd_wr_retry(pfdi[1], pass, x, 1);
+	rd_wr_retry(pfdi[1], "\n", 1, 1);
+	close(pfdi[1]);
+	memset(pass, 0, x);
+	pass = get_FD_pass(pfdo[0]);
+	close(pfdo[0]);
+	waitpid(gpid, &x, 0);
+	if(!pass) goto nomem1;
+	return pass;
+}
+
+/* */
+static char *sGetPass(int minLen, int warnLen, int passFDnumber, char *gpgHomeDir, 
+			char *gpgKeyFile, int passAskTwice, char *passSeedString)
+{
+ 	char *p, *s, *seed;
+	int i, ask2;
+
+	if(passFDnumber < 0) {
+		p = getpass(_("Password: "));
+		ask2 = passAskTwice;
+	} else {
+                p = get_FD_pass(passFDnumber);
+		ask2 = 0;
+	}
+        if(!p) goto nomem;
+	if(gpgKeyFile && gpgKeyFile[0]) {
+		if(ask2) {
+                        i = strlen(p);
+			s = malloc(i + 1);
+			if(!s) goto nomem;
+			strcpy(s, p);
+			p = getpass(_("Retype password: "));
+			if(!p) goto nomem;
+			if(strcmp(s, p)) goto compareErr;
+			memset(s, 0, i);
+			free(s);
+                        ask2 = 0;
+		}
+                p = do_GPG_pipe(p,gpgHomeDir,gpgKeyFile);
+		if(!p) return(NULL);
+		if(!p[0]) {
+                        fprintf(stderr, _("Error: gpg key file decryption failed\n"));
+			return(NULL);
+		}
+	}
+        i = strlen(p);
+	if(i < minLen) {
+		fprintf(stderr, _("Error: Password must be at least %d characters.\n"), minLen);
+		return(NULL);
+	}
+        seed = passSeedString;
+	if(!seed) seed = "";
+	s = malloc(i + strlen(seed) + 1);
+	if(!s) {
+                nomem:
+		fprintf(stderr, _("Error: Unable to allocate memory\n"));
+		return(NULL);
+	}
+        strcpy(s, p);
+	memset(p, 0, i);
+	if(ask2) {
+                p = getpass(_("Retype password: "));
+		if(!p) goto nomem;
+		if(strcmp(s, p)) {
+		        compareErr:
+		        fprintf(stderr, _("Error: Passwords are not identical\n"));
+		        return(NULL);
+		}
+		memset(p, 0, i);
+	}
+	if(i < warnLen) {
+	        fprintf(stderr,
+	              _("\n"
+		        "WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n" 
+		        "\n" 
+	 		"Passwords shorter than %d characters are considered too short and insecure.\n"
+	                "Use of rmd160 password hash permits use of such short passwords for\n"
+	                "compatibility with other systems that do not enforce minimum length.\n"
+	                "Hopefully this message is annoying enough that you discontinue using such\n"
+	        	"short passwords.\n"
+		        "\n"
+		        "WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
+		        "\n")
+	 		, LOOP_PASSWORD_MIN_LENGTH);
+	}
+	strcat(s, seed);
+	return(s);
+}
+
+
+
+
 int
 set_loop (const char *device, const char *file, int offset,
-	  const char *encryption, int *loopro) {
+	  const char *encryption, int pfd, int keysz, int *loopro, 
+	  const char *phash_name, const char *blockmode, char *passIterThousands, 
+	  char *gpgHomeDir, char *gpgKeyFile, int passAskTwice, char *loInitValue,
+	  char *passSeedString)
+{
 	struct loop_info loopinfo;
-	int fd, ffd, mode, i;
-	char *pass;
+	int fd, ffd, mode;
 
 	mode = (*loopro ? O_RDONLY : O_RDWR);
 	if ((ffd = open (file, mode)) < 0) {
@@ -219,13 +513,10 @@
 	*loopro = (mode == O_RDONLY);
 
 	memset (&loopinfo, 0, sizeof (loopinfo));
-	xstrncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
-	if (encryption && (loopinfo.lo_encrypt_type = crypt_type (encryption))
-	    < 0) {
-		fprintf (stderr, _("Unsupported encryption type %s\n"),
-			 encryption);
-		return 1;
-	}
+	snprintf(loopinfo.lo_name, sizeof(loopinfo.lo_name),
+		 "%s-%s", encryption, blockmode);
+	loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
+	loopinfo.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
 	loopinfo.lo_offset = offset;
 
 #ifdef MCL_FUTURE  
@@ -241,24 +532,377 @@
 	}
 #endif
 
-	switch (loopinfo.lo_encrypt_type) {
-	case LO_CRYPT_NONE:
-		loopinfo.lo_encrypt_key_size = 0;
-		break;
+        if(loInitValue) {
+		/* cipher modules are free to do whatever they want with this value */
+		int lo_init = 0;
+		sscanf(loInitValue, "%d", &lo_init);
+		loopinfo.lo_init[0] = lo_init;
+	}
+
+	if (ioctl (fd, LOOP_SET_FD, ffd) < 0) {
+		perror ("ioctl: LOOP_SET_FD");
+		return 1;
+	}
+
+	set_loop_passwd(&loopinfo, pfd, keysz, phash_name, encryption, fd, 
+			ffd, passIterThousands, gpgHomeDir, gpgKeyFile, 
+			passAskTwice, loInitValue, passSeedString);
+
+	if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+		/* Try again with old-style LO_CRYPT_XX if
+                   new-style LO_CRYPT_CRYPTOAPI ioctl didn't work */
+		strncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
+		loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
+		loopinfo.lo_encrypt_type = name_to_id (encryption);
+
+		set_loop_passwd(&loopinfo, pfd, keysz, phash_name, encryption, fd, 
+				ffd, passIterThousands, gpgHomeDir, gpgKeyFile, 
+				passAskTwice, loInitValue, passSeedString);
+
+		if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+			error("The cipher does not exist, or a cipher module "
+			      "needs to be loaded into the kernel");
+			perror ("ioctl: LOOP_SET_STATUS");
+			(void) ioctl (fd, LOOP_CLR_FD, 0);
+			return 1;
+		}
+	}
+	close (fd);
+	close (ffd);
+	if (verbose > 1)
+		printf(_("set_loop(%s,%s,%d): success\n"),
+		       device, file, offset);
+	return 0;
+}
+
+
+
+typedef int (*phash_func_t)(char dest[LO_KEY_SIZE], const char src[], size_t src_len);
+
+#define PASSWDBUFFLEN 130
+
+static int
+phash_rmd160old (char dest[LO_KEY_SIZE], const char src[], size_t src_len)
+{
+  char tmp[PASSWDBUFFLEN] = { 'A', 0, };
+  char key[RMD160_HASH_SIZE * 2] = { 0, };
+
+  strncpy (tmp + 1, src, PASSWDBUFFLEN - 1);
+  tmp[PASSWDBUFFLEN - 1] = '\0';
+  
+  rmd160_hash_buffer(key, src, src_len);
+  rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp, src_len + 1 /* dangerous! */);
+
+  memcpy (dest, key, LO_KEY_SIZE);
+
+  return 0;
+}
+
+static int
+phash_sha256 (char dest[LO_KEY_SIZE], const char src[], size_t src_len)
+{
+  memset (dest, 0, LO_KEY_SIZE);
+  sha256_hash_buffer ((char *) src, src_len, dest, LO_KEY_SIZE);
+  return 0;
+}
+
+static int
+phash_sha384 (char dest[LO_KEY_SIZE], const char src[], size_t src_len)
+{
+  memset (dest, 0, LO_KEY_SIZE);
+  sha384_hash_buffer ((char *) src, src_len, dest, LO_KEY_SIZE);
+  return 0;
+}
+
+static int
+phash_sha512 (char dest[LO_KEY_SIZE], const char src[], size_t src_len)
+{
+  memset (dest, 0, LO_KEY_SIZE);
+  sha512_hash_buffer ((char *) src, src_len, dest, LO_KEY_SIZE);
+  return 0;
+}
+
+static int
+phash_default (char dest[LO_KEY_SIZE], const char src[], size_t src_len)
+{
+  fprintf (stderr, "unknown hash type requested\n");
+  return 1;
+}
+
+static int 
+phash_hexconv(char *keyBuf, const char *keyStr, size_t src_len)
+{
+ 	register int	x, y, z;
+ 	char        	*kp;
+	int 		bufSize = LO_KEY_SIZE;
+	/*
+	 *  Preprocess the key. Uses only 6 bits of each character.
+	 */
+	printf("PANIC! %s\n",keyStr);
+	for(x = 0; x < bufSize; x++) {
+	        keyBuf[x] = 0;
+	}
+	kp = (char *)keyStr;
+	for(x = 0; x < (bufSize * 8); x += 6) {
+	        if(!(*kp)) kp = (char *)keyStr;		// rewind
+	        y = *kp++;
+                if((y >= '0') && (y <= '9')) y -= '0';
+                else if((y >= 'A') && (y <= 'Z')) y -= ('A' - 10);
+                else if((y >= 'a') && (y <= 'z')) y -= ('a' - 36);
+                else if((y == '.') || (y == '/')) y += (62 - '.');
+                else return(0);   /* invalid character */
+	        z = x >> 3;
+                if(z < bufSize) {
+                        keyBuf[z] |= y << (x & 7);
+                }
+                z++;
+                if(z < bufSize) {
+                        keyBuf[z] |= y >> (8 - (x & 7));
+                }
+	}
+        return(1);   /* ok */
+}
+
+static phash_func_t 
+phash_lookup (const char phash_name[])
+{
+  struct {
+    const char *name;
+    phash_func_t func;
+  } func_table[] = {
+    {"rmd160old", phash_rmd160old },
+    {"sha256",    phash_sha256 },
+    {"sha384",    phash_sha384 },
+    {"sha512",    phash_sha512 },
+    {"hexconv",  phash_hexconv },
+    { 0, phash_default }
+  }, *p = func_table;
+
+  for (; p->name; p++)
+    if (!strcmp (phash_name, p->name))
+      break;
+  
+  return p->func;
+}
+
+static int default_keysize_for_cipher(int encrypt_type)
+{
+	int keylength=0,i;
+	for(i=0; crypt_type_tbl[i].id != -1; i++){
+	         if(encrypt_type == crypt_type_tbl[i].id){
+		         keylength = crypt_type_tbl[i].keylength;
+			 break;
+		 }
+	}
+	return keylength;
+}
+
+static int prepare_passwd(char *src, int srcsz, char *dst, int dstsz, const char *phash_name, char *passIterThousands)
+{
+	int ret;
+	int (*hashFunc)(char [], const char [], size_t);
+
+	if(phash_name)
+		hashFunc = phash_lookup (phash_name);
+	else
+	{	hashFunc = phash_sha256;
+		if(dstsz >= 24) hashFunc = phash_sha384;
+		if(dstsz >= 32) hashFunc = phash_sha512;
+	}
+	ret = hashFunc(dst,src,srcsz);
+	if(ret != 0) return ret;
+	if(passIterThousands) {
+		aes_context ctx;
+		unsigned long iter = 0;
+		unsigned char tempkey[32];
+		/*
+                 * Set up AES-256 encryption key using same password and hash function
+                 * as before but with password bit 0 flipped before hashing. That key
+                 * is then used to encrypt actual loop key 'itercountk' thousand times.
+                 */
+                src[0] ^= 1;
+                (*hashFunc)(&tempkey[0], src, srcsz);
+                aes_set_key(&ctx, &tempkey[0], 32, 0);
+                sscanf(passIterThousands, "%lu", &iter);
+                iter *= 1000;
+                while(iter > 0) {
+                	/* encrypt both 128bit blocks with AES-256 */
+                        aes_encrypt(&ctx, dst, dst);
+                        aes_encrypt(&ctx, dst+16, dst+16);
+                        /* exchange upper half of first block with lower half of second block */
+                        memcpy(&tempkey[0], dst+8, 8);
+                        memcpy(dst+8,dst+16, 8);
+                        memcpy(dst+16, &tempkey[0], 8);
+                        iter--;
+                        }
+                 memset(&ctx, 0, sizeof(ctx));
+                 memset(&tempkey[0], 0, sizeof(tempkey));
+	}
+	return ret;
+}
+
+static int get_cipher_info25(const char *requested_cipher, struct cipher_info *res)
+{
+//	char path[PATH_MAX];
+#define BUFFER_SIZE 2000
+	char buf[BUFFER_SIZE];
+	int eof=0;
+	char name[BUFFER_SIZE];
+	int minkey, maxkey;
+	int j;
+	FILE *f;
+	struct {
+		char *string;
+		int *integer;
+		const char *prefix;
+	} fields[] = {{name, NULL, "name         : "},
+		      {NULL, NULL, "module       : "},
+		      {NULL, &res->blocksize, "blocksize    : "},
+		      {NULL, &minkey, "min keysize  : "},
+		      {NULL, &maxkey, "max keysize  : "},
+		      {NULL, &res->ivsize, "ivsize       : "},
+		      {NULL, NULL, "digestsize   : "}};
+	f = fopen("/proc/crypto", "r");
+	
+	if(!f)
+		return -1;
+
+	// CryptoAPI 2.5 doesn't use <name>-<blockmode>, so cut it off
+	if(rindex(requested_cipher,'-') != NULL)
+		*rindex(requested_cipher,'-') = 0;
+
+	// Outer loop searches the requested cipher
+	while(!eof)
+	{	
+		// Inner loop parses individual crypto entries
+		while(!(eof = (fgets(buf, sizeof(buf), f) == NULL))) {
+			int i;
+			for (i = 0; i < sizeof(fields)/sizeof(fields[0]); i++) {
+				int len = strlen(fields[i].prefix);
+				if (strncmp(buf, fields[i].prefix, len) == 0) {
+					if(fields[i].string != NULL)
+					{
+						int slen = strlen(buf+len)-1;
+						strncpy(fields[i].string,buf+len,slen<BUFFER_SIZE?slen:BUFFER_SIZE);
+						fields[i].string[slen<BUFFER_SIZE?slen:BUFFER_SIZE]=0;
+					}
+					if(fields[i].integer != NULL)
+						*fields[i].integer = strtoul(&buf[len], NULL, 0);
+					break;
+				}
+			}
+
+			// No prefix found? Empty line?
+			if(buf[0] == 0xA)
+				break; 
+
+		}
+		if(strcmp(name,requested_cipher) == 0) break;	
+	}
+	if (eof) 		// Cipher not found
+		return -1;
+
+	res->key_schedule_size = 0;
+
+	// convert keysize mask
+	res->keysize_mask = 0;
+	for(j=minkey-1; j < maxkey; j++)
+		res->keysize_mask = res->keysize_mask | (1 << j);
+	return 0;
+}
+
+static int get_cipher_info24(const char *name, struct cipher_info *res)
+{
+	char path[PATH_MAX];
+	char buf[2000];
+	FILE *f;
+	struct {
+		int *out;
+		const char *prefix;
+	} fields[] = {{&res->blocksize, "blocksize:"},
+		      {&res->keysize_mask, "keysize_mask:"},
+		      {&res->ivsize, "ivsize:"},
+		      {&res->key_schedule_size, "key_schedule_size:"}};
+	snprintf(path, sizeof(path), "/proc/crypto/cipher/%s", name);
+	f = fopen(path, "r");
+	while(f && fgets(buf, sizeof(buf), f)) {
+		int i;
+		for (i = 0; i < sizeof(fields)/sizeof(fields[0]); i++) {
+			int len = strlen(fields[i].prefix);
+			if (strncmp(buf, fields[i].prefix, len) == 0) {
+				*fields[i].out = strtoul(&buf[len+1], NULL, 0);
+				break;
+			}
+		}
+		
+	}
+	if (!f) 
+		return -1;
+	return 0;
+}
+
+static int get_cipher_info(const char *name, struct cipher_info *res)
+{
+	int ret;
+	ret = get_cipher_info25(name, res);
+	if(ret == -1)
+		return get_cipher_info24(name,res);	// Fallback to 2.4.x
+	else
+		return ret;
+
+}
+
+int set_loop_passwd(struct loop_info *loopinfo, int pfd, int keysz,
+			   const char *phash_name, const char *encryption, 
+			   int fd, int ffd, char *passIterThousands, char *gpgHomeDir,
+			   char *gpgKeyFile, int passAskTwice, char *loInitValue,
+			   char *passSeedString)
+{
+	int i;
+	char *pass;
+	struct cipher_info info;
+
+	if(loopinfo->lo_encrypt_type == LO_CRYPT_NONE)
+	{
+		loopinfo->lo_encrypt_key_size = 0;
+		return 0;
+	}
+	if(loopinfo->lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
+	{ // before we ask for a pwd make sure we can support that enctype
+		/* Give the kernel an opportunity to load the cipher */
+		(void) ioctl (fd, LOOP_SET_STATUS, loopinfo);
+		if (get_cipher_info(loopinfo->lo_name, &info) < 0) {
+			return 1;
+		}
+	}
+	
+	pass = sGetPass(0,0,pfd,gpgHomeDir,gpgKeyFile, passAskTwice,
+			passSeedString);
+	if(keysz == -1)		// -k auto
+	{
+		keysz = 16*8;
+		if(strlen(pass) >= 32) keysz = 24*8;
+		if(strlen(pass) >= 43) keysz = 43*8;
+		if(verbose > 1)
+			printf("auto keysiez selection %d\n",keysz);
+	}
+
+	switch (loopinfo->lo_encrypt_type) {
 	case LO_CRYPT_XOR:
-		pass = getpass (_("Password: "));
-		xstrncpy (loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE);
-		loopinfo.lo_encrypt_key_size = strlen(loopinfo.lo_encrypt_key);
+          /* WARNING: xgetpass() can return massive amounts of data,
+           * not only 128 bytes like the original getpass(3) */
+		xstrncpy (loopinfo->lo_encrypt_key, pass, LO_KEY_SIZE);
+		loopinfo->lo_encrypt_key_size = strlen(loopinfo->lo_encrypt_key);
 		break;
 	case LO_CRYPT_DES:
-		pass = getpass (_("Password: "));
-		strncpy (loopinfo.lo_encrypt_key, pass, 8);
-		loopinfo.lo_encrypt_key[8] = 0;
-		loopinfo.lo_encrypt_key_size = 8;
+		printf(_("WARNING: Use of DES is depreciated.\n"));
+		strncpy (loopinfo->lo_encrypt_key, pass, 8);
+		loopinfo->lo_encrypt_key[8] = 0;
+		loopinfo->lo_encrypt_key_size = 8;
 		pass = getpass (_("Init (up to 16 hex digits): "));
 		for (i = 0; i < 16 && pass[i]; i++)
 			if (isxdigit (pass[i])) {
-				loopinfo.lo_init[i >> 3] |= (pass[i] > '9' ?
+				loopinfo->lo_init[i >> 3] |= (pass[i] > '9' ?
 				  (islower (pass[i]) ? toupper (pass[i]) :
 				   pass[i])-'A'+10 : pass[i]-'0') << (i&7) * 4;
 			} else {
@@ -267,48 +911,67 @@
 				return 1;
 			}
 		break;
+	case LO_CRYPT_CRYPTOAPI:
+		if (keysz > 0 &&
+		    !((1 << ((keysz / 8) - 1)) & info.keysize_mask)) {
+			error("The specified keysize is not supported by "
+			      "the selected cipher");
+			keysz = 0;
+		}
+
+		while (keysz <= 0 ||
+		       !((1 << ((keysz / 8) - 1)) & info.keysize_mask)) {
+			int i = 0;
+			int available = 0;
+			char keysize[200];
+			printf("Available keysizes (bits): ");
+			for (; i < 32; i++) {
+				if (info.keysize_mask & (1 << i)) {
+					printf("%d ", 8*(i+1));
+					available = 1;
+				}
+			}
+			if (!available) {
+				printf("none");
+			}
+			printf("\nKeysize: ");
+			fgets(keysize, sizeof(keysize), stdin);
+			keysz = atoi(keysize);
+		}
+		/* fall through */
+	case LO_CRYPT_FISH2:
+	case LO_CRYPT_BLOW:
+	case LO_CRYPT_IDEA:
+	case LO_CRYPT_CAST128:
+        case LO_CRYPT_SERPENT:
+        case LO_CRYPT_MARS:
+        case LO_CRYPT_RC6:
+        case LO_CRYPT_3DES:
+        case LO_CRYPT_DFC:
+        case LO_CRYPT_RIJNDAEL:
+		
+		if(keysz) 
+			loopinfo->lo_encrypt_key_size = keysz/8;
+		else
+			loopinfo->lo_encrypt_key_size = default_keysize_for_cipher(loopinfo->lo_encrypt_type);
+
+		printf("%s\n",pass?pass:"NULL");
+		memset(loopinfo->lo_encrypt_key,0,LO_KEY_SIZE);
+		prepare_passwd(pass,strlen(pass),
+				loopinfo->lo_encrypt_key,loopinfo->lo_encrypt_key_size,
+				phash_name,passIterThousands);
+
+		memset(pass, 0, strlen(pass));   /* erase original password */
+		break;
 	default:
 		fprintf (stderr,
 			 _("Don't know how to get key for encryption system %d\n"),
-			 loopinfo.lo_encrypt_type);
-		return 1;
-	}
-	if (ioctl (fd, LOOP_SET_FD, ffd) < 0) {
-		perror ("ioctl: LOOP_SET_FD");
+			 loopinfo->lo_encrypt_type);
 		return 1;
 	}
-	if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
-		(void) ioctl (fd, LOOP_CLR_FD, 0);
-		perror ("ioctl: LOOP_SET_STATUS");
-		return 1;
-	}
-	close (fd);
-	close (ffd);
-	if (verbose > 1)
-		printf(_("set_loop(%s,%s,%d): success\n"),
-		       device, file, offset);
-	return 0;
+        return 0;
 }
 
-int 
-del_loop (const char *device) {
-	int fd;
-
-	if ((fd = open (device, O_RDONLY)) < 0) {
-		int errsv = errno;
-		fprintf(stderr, _("loop: can't delete device %s: %s\n"),
-			device, strerror (errsv));
-		return 1;
-	}
-	if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
-		perror ("ioctl: LOOP_CLR_FD");
-		return 1;
-	}
-	close (fd);
-	if (verbose > 1)
-		printf(_("del_loop(%s): success\n"), device);
-	return 0;
-}
 
 #else /* no LOOP_SET_FD defined */
 static void
@@ -320,7 +983,8 @@
 
 int
 set_loop (const char *device, const char *file, int offset,
-	  const char *encryption, int *loopro) {
+	  const char *encryption, int pfd, int *loopro, const char *phash_name,
+	  const char *blockmode) {
 	mutter();
 	return 1;
 }
@@ -349,12 +1013,60 @@
 int verbose = 0;
 static char *progname;
 
+static struct option longopts[] = {
+	{ "blockmode", 0, 0, 'b' },
+	{ "delete", 0, 0, 'd' },
+	{ "detach", 0, 0, 'd' },
+	{ "encryption", 1, 0, 'e' },
+	{ "help", 0, 0, 'h' },
+	{ "offset", 1, 0, 'o' },
+	{ "pass-fd", 1, 0, 'p' },
+	{ "phash", 1, 0, 'P' },
+	{ "verbose", 0, 0, 'v' },
+	{ "keybits", 1, 0, 'k' },
+	{ NULL, 0, 0, 0 }
+};
+
 static void
 usage(void) {
-	fprintf(stderr, _("usage:\n\
+	fprintf(stderr, 
+_("usage:\n\
   %s loop_device                                      # give info\n\
   %s -d loop_device                                   # delete\n\
-  %s [ -e encryption ] [ -o offset ] loop_device file # setup\n"),
+  %s [ options ] loop_device file                     # setup\n\
+    where options include\n\
+    --blockmode <mode>, -b <mode>\n\
+    	use specified blockmode for cipher.\n\
+    --offset <num>, -o <num>\n\
+        start at offset <num> into file.\n\
+    --pass-fd <num>, -p <num>\n\
+        read passphrase from file descriptor <num>\n\
+        instead of the terminal.\n\
+    --encryption <cipher>, -e <cipher>\n\
+        encrypt with <cipher>.\n\
+        Check /proc/crypto/cipher for available ciphers.\n\
+    --keybits <num>, -k <num>\n\
+        specify number of bits in the hashed key given\n\
+        to the cipher.  Some ciphers support several key\n\
+        sizes and might be more efficient with a smaller\n\
+        key size.  Key sizes < 128 are generally not\n\
+        recommended\n\
+    --phash <hash>, -P <hash>\n\
+        specify <hash> to use for hashing the passphrase\n\
+        (supported: rmd160old, sha256, sha384, sha512, hexconv)\n\
+    --passIter <iter>, -C <iter>\n\
+        specify numbers of thousands of iterations of AES supported hashing
+        additionally to normal password hashing\n\
+    --gpgHomeDir <homedir>, -G <homedir>\n\
+        home directory for GPG operations\n\
+    --gpgKeyFile <keyfile>, -K <keyfile>\n\
+	keyfile for GPG operations\n\
+    --passAskTwice, -T\n\
+	ask twice for the password and check for equality\n\
+    --passSeedString <seed>, -S <seed>\n\
+	prepend to passwd\n\
+    --loInit, -I\n\
+        supply additionally infos to cipher in loInit[0]\n"),
 		progname, progname, progname);
 	exit(1);
 }
@@ -386,51 +1098,232 @@
 	fprintf (stderr, "\n");
 }
 
+void
+show_all_loops(void)
+{
+ 	char dev[20];
+ 	char *lfmt[] = { "/dev/loop%d", "/dev/loop/%d" };
+ 	int i, j, fd, x;
+ 	struct stat statbuf;
+ 	struct loop_info loopinfo;
+
+	for(i = 0; i < 256; i++) {
+	        for(j = (sizeof(lfmt) / sizeof(lfmt[0])) - 1; j >= 0; j--) {
+	                sprintf(dev, lfmt[j], i);
+	                if(stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+	                        fd = open(dev, O_RDONLY);
+	                        if(fd >= 0) {
+	                                x = ioctl(fd, LOOP_GET_STATUS, &loopinfo);
+	                                close(fd);
+ 	                                if(x == 0) {
+		                                show_loop(dev);
+   			                        j = 0;
+                                        }
+                                }
+			}
+	        }
+	}
+}
+
+int
+read_options_from_fstab(char *loopToFind, char **partitionPtr, char **offsetPtr, char **encryptionPtr,
+			char **passSeedString, char **passHashFuncName, 
+			char **loInitValue, char **gpgKeyFile, char **gpgHomeDir,
+			char **passIterThousands)
+{
+ 	FILE *f;
+ 	struct mntent *m;
+	int y, foundMatch = 0;
+        char *opt;
+        struct options {
+                char *name;	/* name of /etc/fstab option */
+		        char **dest;    /* destination where it is written to */
+	        char *line;     /* temp */
+	};
+	struct options tbl[] = {
+	        { "device/file name ",  partitionPtr }, /* must be index 0 */
+	 	{ "loop=",              &loopToFind },  /* must be index 1 */
+ 		{ "offset=",		offsetPtr },
+		{ "encryption=",	encryptionPtr },
+   		{ "pseed=",     	passSeedString },
+                { "phash=",             passHashFuncName },
+ 		{ "loinit=",		loInitValue },
+   	        { "gpgkey=",		gpgKeyFile }, 
+                { "gpghome=",   	gpgHomeDir },
+                { "itercountk=",	passIterThousands },
+        };
+        struct options *p;
+
+	if (!(f = setmntent("/etc/fstab", "r"))) {
+	        fprintf(stderr, _("Error: unable to open /etc/fstab for reading\n"));
+	  	return 0;
+        }
+        while ((m = getmntent(f)) != NULL) {
+		tbl[0].line = xstrdup(m->mnt_fsname);
+		p = &tbl[1];
+		do {
+                    	p->line = NULL;
+		} while (++p < &tbl[sizeof(tbl) / sizeof(struct options)]);
+		for (opt = strtok(xstrdup(m->mnt_opts), ","); opt != NULL; opt = strtok(NULL, ",")) {
+			p = &tbl[1];
+			do {
+                            	y = strlen(p->name);
+                                if (!strncmp(opt, p->name, y))
+                                        p->line = opt + y;
+			} while (++p < &tbl[sizeof(tbl) / sizeof(struct options)]);
+		}
+                if (tbl[1].line && !strcmp(loopToFind, tbl[1].line)) {
+			if (++foundMatch > 1) {
+                                fprintf(stderr, _("Error: multiple loop=%s options found in /etc/fstab\n"), loopToFind);
+                                endmntent(f);
+                                return 0;
+			}
+                        p = &tbl[0];
+			do {
+                            	if (!*p->dest && p->line) {
+                                        *p->dest = p->line;
+                                        if (verbose)
+                                                printf(_("using %s%s from /etc/fstab\n"), p->name, p->line);
+                                }
+                        } while (++p < &tbl[sizeof(tbl) / sizeof(struct options)]);
+		}
+	}
+	endmntent(f);
+	if (foundMatch == 0) {
+	        fprintf(stderr, _("Error: loop=%s option not found in /etc/fstab\n"), loopToFind);
+	}
+	return foundMatch;
+}
+
+
 int
 main(int argc, char **argv) {
-	char *offset, *encryption;
-	int delete,off,c;
+	char *offset = 0, *encryption = 0, *passfd = 0, *keysize = 0, *phash_name = 0, *blockmode = 0;
+	int delete = 0, off = 0, c = 0,option_a=0,option_F=0;
+	char *passIterThousands = NULL;
+	char *gpgHomeDir = NULL;
+	char *gpgKeyFile = NULL;
+	char *passSeedString = NULL;
+	char *loInitValue = NULL;
+	char *partitionName = NULL;
+	int pfd = -1;
 	int res = 0;
 	int ro = 0;
+	int keysz = 0;
+	int passAskTwice = 0;
 
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 
-	delete = off = 0;
-	offset = encryption = NULL;
 	progname = argv[0];
-	while ((c = getopt(argc,argv,"de:o:v")) != -1) {
+	while ((c = getopt_long(argc,argv,"aC:b:de:FG:H:I:K:h:k:o:p:P:S:Tv",
+				longopts, NULL)) != -1) {
 		switch (c) {
+   	        case 'a':               /* show status of all loops */
+			option_a = 1;
+			break;
+	        case 'C':
+			passIterThousands = optarg;
+			break;
+		case 'b':
+			blockmode = optarg;
+			break;
 		case 'd':
 			delete = 1;
 			break;
 		case 'e':
 			encryption = optarg;
 			break;
+		case 'F':     		/* read loop related options from /etc/fstab */
+			option_F = 1;
+			break;
+        	case 'G':     		/* GnuPG home dir */
+                        gpgHomeDir = optarg;
+   	                break;
+	        case 'I':     		/* lo_init[0] value (in string form)  */
+		        loInitValue = optarg;
+                        break;
+                case 'K':     		/* GnuPG key file name */
+                        gpgKeyFile = optarg;
+                        break;
+		case 'k':
+		        keysize = optarg;
+			break;
 		case 'o':
 			offset = optarg;
 			break;
+		case 'p':
+		        passfd = optarg;
+			break;
+		case 'P':
+		        phash_name = optarg;
+			break;
+	        case 'S':     		/* optional seed for passphrase */
+                        passSeedString = optarg;
+	                break;
+        	case 'T':     		/* ask passphrase _twice_ */
+                        passAskTwice = 1;
+   	                break;
 		case 'v':
-			verbose = 1;
+			verbose++;
 			break;
 		default:
 			usage();
 		}
 	}
 	if (argc == 1) usage();
-	if ((delete && (argc != optind+1 || encryption || offset)) ||
+	if (option_a) {
+		if (delete || (argc != optind)) usage();
+		show_all_loops();
+		exit(0);
+	}
+	printf("%d %d\n",optind,argc);
+	if ((delete && (argc != optind+1 || encryption || offset || passfd || option_a || option_F)) ||
 	    (!delete && (argc < optind+1 || argc > optind+2)))
 		usage();
+        if (argc > optind+1)
+                partitionName = argv[optind+1];
+        if (option_F && (read_options_from_fstab(argv[optind], &partitionName, 
+        					 &offset, &encryption, 
+        					 &passSeedString, &phash_name, 
+        					 &loInitValue, &gpgHomeDir, 
+        					 &gpgKeyFile, &passIterThousands) != 1))
+		exit(1);
+                        
 	if (argc == optind+1) {
 		if (delete)
 			res = del_loop(argv[optind]);
 		else
-			res = show_loop(argv[optind]);
+			if(!option_F)
+				res = show_loop(argv[optind]);
 	} else {
 		if (offset && sscanf(offset,"%d",&off) != 1)
 			usage();
-		res = set_loop(argv[optind],argv[optind+1],off,encryption,&ro);
+		if (passfd && sscanf(passfd,"%d",&pfd) != 1)
+		        usage();
+		if (keysize)
+		{
+			if(strcmp(keysize,"auto") == 0)
+				keysz = -1;
+			else 
+			if (sscanf(keysize,"%d",&keysz) != 1)
+			        usage();
+		}
+		if (!blockmode || strlen(blockmode) != 3) {
+//			fprintf(stderr, "no block mode given or invalid blockmode, defaulting to cbc.\n");
+			blockmode = "cbc";
+		}
+		if (!strcmp(blockmode, "ctr")) {
+			fprintf(stderr, "counter mode is not recommend for file system encryption as it may be insecure. consider using rtc mode or another blockmode.\n");
+			return -1;
+		}
+			
+		res = set_loop(argv[optind], partitionName, off,
+			       encryption, pfd, keysz, &ro,
+			       phash_name,
+			       blockmode,passIterThousands,gpgHomeDir,gpgKeyFile,
+			       passAskTwice, loInitValue, passSeedString);
 	}
 	return res;
 }
@@ -446,3 +1339,32 @@
 }
 #endif
 #endif
+
+
+
+static int 
+name_to_id(const char *name) 
+{
+	int i;
+
+	if (name) {
+		for (i = 0; crypt_type_tbl[i].id != -1; i++)
+			if (!strcasecmp (name, crypt_type_tbl[i].name))
+				return crypt_type_tbl[i].id;
+	} else
+		return LO_CRYPT_NONE;
+	return LO_CRYPT_CRYPTOAPI;
+}
+
+#ifdef MAIN
+static char *
+id_to_name(int id) {
+	int i;
+
+	for (i = 0; crypt_type_tbl[i].id != -1; i++)
+		if (id == crypt_type_tbl[i].id)
+			return crypt_type_tbl[i].name;
+	return "undefined";
+}
+#endif
+
diff -ru --new-file util-linux-2.11y/mount/lomount.h util-linux-AES/mount/lomount.h
--- util-linux-2.11y/mount/lomount.h	Fri Dec  8 19:08:02 2000
+++ util-linux-AES/mount/lomount.h	Sun Feb  9 21:19:32 2003
@@ -1,5 +1,9 @@
 extern int verbose;
-extern int set_loop (const char *, const char *, int, const char *, int *);
+extern int set_loop (const char *device, const char *file, int offset,
+          const char *encryption, int pfd, int keysz, int *loopro, 
+          const char *phash_name, const char *blockmode, char *passIterThousands, 
+          char *gpgHomeDir, char *gpgKeyFile, int passAskTwice, char *loInitValue,
+          char *passSeedString);
 extern int del_loop (const char *);
 extern int is_loop_device (const char *);
 extern char * find_unused_loop_device (void);
diff -ru --new-file util-linux-2.11y/mount/loop-aes-conversion util-linux-AES/mount/loop-aes-conversion
--- util-linux-2.11y/mount/loop-aes-conversion	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/loop-aes-conversion	Mon Feb 10 01:37:23 2003
@@ -0,0 +1,8 @@
+Loop AES styled losetup conversion "guide":
+
+loop-AES			util-linux-2.12
+--------------------------------------------------------------------
+losetup -e aes128		losetup -e rijndael -k 128 -P sha256
+losetup -e aes192		losetup -e rijndael -k 192 -P sha384
+losetup -e aes256		losetup -e rijndael -k 256 -P sha512
+losetup -e aes			losetup -e rijndael -k auto -P hexconv
diff -ru --new-file util-linux-2.11y/mount/losetup.8 util-linux-AES/mount/losetup.8
--- util-linux-2.11y/mount/losetup.8	Fri Aug 11 13:11:30 2000
+++ util-linux-AES/mount/losetup.8	Wed Feb  5 15:21:34 2003
@@ -10,6 +10,9 @@
 ] [
 .B \-o
 .I offset
+] [
+.B \-p
+.I num
 ]
 .I loop_device file
 .br
@@ -26,9 +29,9 @@
 \fIloop_device\fP argument is given, the status of the corresponding loop
 device is shown.
 .SH OPTIONS
-.IP \fB\-d\fP
+.IP "\fB\-\-delete, \-\-detach, \-d\fP"
 detach the file or device associated with the specified loop device.
-.IP "\fB\-e \fIencryption\fP"
+.IP "\fB\-\-encryption, \-e \fIencryption\fP"
 .RS
 enable data encryption. The following keywords are recognized:
 .IP \fBNONE\fP
@@ -36,16 +39,79 @@
 .PD 0
 .IP \fBXOR\fP
 use a simple XOR encryption.
+.IP \fBaes\fP
+use Advanced Encryption Standard encryption. AES encryption is only available 
+if you are using the international kernel and AES encryption has been enabled 
+in the Crypto API.
+enabled in the Crypto API.
+.IP \fBblowfish\fP
+use Blowfish encryption. Blowfish encryption is only available if you
+are using the international kernel and Blowfish encryption has been
+enabled in the Crypto API.
+.IP \fBtwofish\fP
+use Twofish encryption. Twofish encryption is only available if you
+are using the international kernel and Twofish encryption has been
+enabled in the Crypto API.
+.IP \fBcast5\fP
+use CAST5 encryption. CAST5 encryption is only available if you
+are using the international kernel and CAST5 encryption has been
+enabled in the Crypto API.
 .IP \fBDES\fP
 use DES encryption. DES encryption is only available if the optional
 DES package has been added to the kernel. DES encryption uses an additional
 start value that is used to protect passwords against dictionary
-attacks.
+attacks. Use of DES is deprecated.
+.IP \fBdes_ede3\fP
+use 3DES encryption. 3DES encryption is only available if you
+are using the international kernel and 3DES encryption has been
+enabled in the Crypto API.
+.IP \fBdfc\fP
+use DFC encryption. DFC encryption is only available if you
+are using the international kernel and DFC encryption has been
+enabled in the Crypto API.
+.IP \fBidea\fP
+use IDEA encryption. IDEA encryption is only available if you
+are using the international kernel and IDEA encryption has been
+enabled in the Crypto API.
+.IP \fBmars\fP
+use MARS encryption. MARS encryption is only available if you
+are using the international kernel and MARS encryption has been
+enabled in the Crypto API.
+.IP \fBrc5\fP
+use RC5 encryption. RC5 encryption is only available if you
+are using the international kernel and RC5 encryption has been
+enabled in the Crypto API.
+.IP \fBrc6\fP
+use RC6 encryption. RC6 encryption is only available if you
+are using the international kernel and RC6 encryption has been
+enabled in the Crypto API.
+.IP \fBserpent\fP
+use Serpent encryption. Serpent encryption is only available if you
+are using the international kernel and Serpent encryption has been
+enabled in the Crypto API.
 .PD
 .RE
-.IP "\fB\-o \fIoffset\fP"
+.IP "\fB\-\-offset, \-o \fIoffset\fP"
 the data start is moved \fIoffset\fP bytes into the specified file or
 device.
+.IP "\fB\-\-pass-fd, \-p \fInum\fP"
+read the passphrase from file descriptor \fInum\fP instead of the
+terminal.
+.IP "\fB\-\-keybits, \-k \fInum\fP"
+set the number of bits to use in key to \fInum\fP.
+.IP "\fB\-\-phash, \-P \fIhash\fP"
+.RS
+specify \fhash\fP to use for hashing the passphrase. The following hash functions are supported:
+.IP \fBrmd160old\fP
+rmd160 (default).
+.PD 0
+.IP \fBsha256\fP
+sha256
+.IP \fBsha384\fP
+sha386
+.IP \fBsha512\fP
+sha512
+
 .SH RETURN VALUE
 .B losetup
 returns 0 on success, nonzero on failure. When
@@ -58,35 +124,54 @@
 .SH FILES
 .nf
 /dev/loop0,/dev/loop1,...   loop devices (major=7)
+/proc/crypto/cipher/*       available ciphers
 .fi
 .SH EXAMPLE
-If you are using the loadable module you must have the module loaded
-first with the command
+If you are using the loadable module you must have the modules loaded
+first with the commands:
+
+.nf
 .IP
-# insmod loop.o
+insmod loop.o
+insmod cryptoapi.o
+insmod cryptoloop.o
+insmod cipher-twofish.o
+.fi
+
 .LP
 The following commands can be used as an example of using the loop device.
+
 .nf
 .IP
 dd if=/dev/zero of=/file bs=1k count=100
-losetup -e des /dev/loop0 /file
-Password:
-Init (up to 16 hex digits):
+losetup -e twofish -k 128 /dev/loop0 /file
+Password :
 mkfs -t ext2 /dev/loop0 100
 mount -t ext2 /dev/loop0 /mnt
  ...
 umount /dev/loop0
 losetup -d /dev/loop0
 .fi
+
 .LP
-If you are using the loadable module you may remove the module with
-the command
+If you are using the loadable module you may remove the modules with
+the commands:
+
+.nf
 .IP
-# rmmod loop
-.LP
+rmmod loop.o
+rmmod cryptoapi.o
+rmmod cryptoloop.o
+rmmod cipher-twofish.o
 .fi
-.SH RESTRICTION
-DES encryption is painfully slow. On the other hand, XOR is terribly weak.
+
+.SH RESTRICTIONS
+DES encryption is painfully slow. On the other hand, XOR is terribly
+weak. Both are insecure nowadays. Some ciphers require a licence for
+you to be allowed to use them.
+.SH BUGS
+RC5 is currently broken and cannot be used.
+
 .SH AUTHORS
 .nf
 Original version: Theodore Ts'o <tytso@athena.mit.edu>
diff -ru --new-file util-linux-2.11y/mount/loumount.c util-linux-AES/mount/loumount.c
--- util-linux-2.11y/mount/loumount.c	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/loumount.c	Thu Feb  6 23:27:00 2003
@@ -0,0 +1,78 @@
+/*
+ *  loumount.c
+ *
+ *  This code was extracted to separate file from lomount.c so that umount
+ *  program doesn't have to link with all loop related setup code
+ */
+
+#define PROC_DEVICES	"/proc/devices"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysmacros.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <locale.h>
+
+#include "loop.h"
+#include "lomount.h"
+#include "xstrncpy.h"
+#include "nls.h"
+
+int
+is_loop_device (const char *device) {
+	struct stat statbuf;
+	int loopmajor;
+#if 1
+	loopmajor = 7;
+#else
+	FILE *procdev;
+	char line[100], *cp;
+
+	loopmajor = 0;
+	if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
+		while (fgets (line, sizeof(line), procdev)) {
+			if ((cp = strstr (line, " loop\n")) != NULL) {
+				*cp='\0';
+				loopmajor=atoi(line);
+				break;
+			}
+		}
+		fclose(procdev);
+	}
+#endif
+	return (loopmajor && stat(device, &statbuf) == 0 &&
+		S_ISBLK(statbuf.st_mode) &&
+		major(statbuf.st_rdev) == loopmajor);
+}
+
+int 
+del_loop (const char *device) {
+	int fd;
+
+	if ((fd = open (device, O_RDONLY)) < 0) {
+		int errsv = errno;
+		fprintf(stderr, _("loop: can't delete device %s: %s\n"),
+			device, strerror (errsv));
+		return 1;
+	}
+	if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
+		perror ("ioctl: LOOP_CLR_FD");
+		return 1;
+	}
+	close (fd);
+	if (verbose > 1)
+		printf(_("del_loop(%s): success\n"), device);
+	return 0;
+}
diff -ru --new-file util-linux-2.11y/mount/mount.8 util-linux-AES/mount/mount.8
--- util-linux-2.11y/mount/mount.8	Sat Nov 23 17:16:52 2002
+++ util-linux-AES/mount/mount.8	Wed Feb  5 15:21:35 2003
@@ -268,6 +268,12 @@
 .B \-v
 Verbose mode.
 .TP
+.B \-p "\fInum\fP"
+If the mount requires a passphrase to be entered, read it from file
+descriptor
+.IR num\fP
+instead of from the terminal.
+.TP
 .B \-a
 Mount all filesystems (of the given types) mentioned in
 .IR fstab .
@@ -622,6 +628,15 @@
 .BR noexec ", " nosuid ", and " nodev
 (unless overridden by subsequent options, as in the option line
 .BR users,exec,dev,suid ).
+.TP
+.B encryption
+Specifies an encryption algorithm to use.  Used in conjunction with the
+.BR loop " option."
+.TP
+.B keybits
+Specifies the key size to use for an encryption algorithm. Used in conjunction
+with the
+.BR loop " and " encryption " options."
 .RE
 .TP
 .B \-\-bind
@@ -1673,7 +1688,10 @@
 .BR loop ", " offset " and " encryption ,
 that are really options to
 .BR losetup (8).
-If no explicit loop device is mentioned
+If the mount requires a passphrase, you will be prompted for one unless
+you specify a file descriptor to read from instead with the 
+.BR \-\-pass-fd
+option. If no explicit loop device is mentioned
 (but just an option `\fB\-o loop\fP' is given), then
 .B mount
 will try to find some unused loop device and use that.
diff -ru --new-file util-linux-2.11y/mount/mount.c util-linux-AES/mount/mount.c
--- util-linux-2.11y/mount/mount.c	Fri Nov  1 02:00:50 2002
+++ util-linux-AES/mount/mount.c	Wed Feb 12 17:05:12 2003
@@ -110,6 +110,9 @@
 /* True if ruid != euid.  */
 static int suid = 0;
 
+/* Contains the fd no. to read the passphrase from, if any */
+static int pfd = -1;
+
 /* Map from -o and fstab option strings to the flag argument to mount(2).  */
 struct opt_map {
   const char *opt;		/* option name */
@@ -189,7 +192,9 @@
 };
 
 static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
-  *opt_speed;
+  *opt_keybits, *opt_speed, *opt_phash, *opt_blockmode;
+static char *passSeedString, *loInitValue;
+static char *gpgKeyFile, *gpgHomeDir, *passIterThousands;
 
 static struct string_opt_map {
   char *tag;
@@ -200,7 +205,15 @@
   { "vfs=",	1, &opt_vfstype },
   { "offset=",	0, &opt_offset },
   { "encryption=", 0, &opt_encryption },
+  { "keybits=", 0, &opt_keybits },
+  { "phash=", 0, &opt_phash },
   { "speed=", 0, &opt_speed },
+  { "blockmode=", 0, &opt_blockmode },
+  { "pseed=",   1, &passSeedString },
+  { "loinit=",  0, &loInitValue },
+  { "gpgkey=",  0, &gpgKeyFile }, 
+  { "gpghome=", 0, &gpgHomeDir }, 
+  { "itercountk=", 1, &passIterThousands },
   { NULL, 0, NULL }
 };
 
@@ -550,7 +563,7 @@
 static int
 loop_check(char **spec, char **type, int *flags,
 	   int *loop, char **loopdev, char **loopfile) {
-  int looptype, offset;
+  int looptype, offset, keybits;
 
   /*
    * In the case of a loop mount, either type is of the form lo@/dev/loop5
@@ -593,7 +606,11 @@
       if (verbose)
 	printf(_("mount: going to use the loop device %s\n"), *loopdev);
       offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0;
-      if (set_loop (*loopdev, *loopfile, offset, opt_encryption, &loopro)) {
+      keybits = opt_keybits ? strtoul(opt_keybits, NULL, 0) : 0;
+      if (set_loop (*loopdev, *loopfile, offset, opt_encryption, pfd, 
+		    keybits, &loopro,
+		    opt_phash, opt_blockmode, passIterThousands, gpgHomeDir,
+		    gpgKeyFile, 0, loInitValue, passSeedString)) {
 	if (verbose)
 	  printf(_("mount: failed setting up loop device\n"));
 	return EX_FAIL;
@@ -1356,6 +1373,7 @@
 	{ "rw", 0, 0, 'w' },
 	{ "options", 1, 0, 'o' },
 	{ "test-opts", 1, 0, 'O' },
+	{ "pass-fd", 1, 0, 'p' },
 	{ "types", 1, 0, 't' },
 	{ "bind", 0, 0, 128 },
 	{ "replace", 0, 0, 129 },
@@ -1392,7 +1410,7 @@
 	  "       mount --move olddir newdir\n"
 	  "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
 	  "or by label, using  -L label  or by uuid, using  -U uuid .\n"
-	  "Other options: [-nfFrsvw] [-o options].\n"
+	  "Other options: [-nfFrsvw] [-o options] [-p num].\n"
 	  "For many more details, say  man 8 mount .\n"
 	));
 /*
@@ -1408,6 +1426,7 @@
 	int c, result = 0, specseen;
 	char *options = NULL, *test_opts = NULL, *spec, *node;
 	char *volumelabel = NULL;
+	char *passfd = NULL;
 	char *uuid = NULL;
 	char *types = NULL;
 	struct mntentchn *mc;
@@ -1431,7 +1450,7 @@
 	initproctitle(argc, argv);
 #endif
 
-	while ((c = getopt_long (argc, argv, "afFhlL:no:O:rsU:vVwt:",
+	while ((c = getopt_long (argc, argv, "afFhlL:no:O:p:rsU:vVwt:",
 				 longopts, NULL)) != -1) {
 		switch (c) {
 		case 'a':	       /* mount everything in fstab */
@@ -1467,6 +1486,9 @@
 			else
 				test_opts = xstrdup(optarg);
 			break;
+		case 'p':               /* read passphrase from given fd */
+		        passfd = optarg;
+			break;
 		case 'r':		/* mount readonly */
 			readonly = 1;
 			readwrite = 0;
@@ -1575,6 +1597,9 @@
 			printf(_("mount: mounting %s\n"), spec);
 	} else
 		spec = NULL;		/* just for gcc */
+
+	if (passfd && sscanf(passfd,"%d",&pfd) != 1)
+	        die (EX_USAGE, _("mount: argument to --pass-fd or -p must be a number"));
 
 	switch (argc+specseen) {
 	case 0:
diff -ru --new-file util-linux-2.11y/mount/rmd160.c util-linux-AES/mount/rmd160.c
--- util-linux-2.11y/mount/rmd160.c	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/rmd160.c	Mon Jan  6 21:59:33 2003
@@ -0,0 +1,532 @@
+/* rmd160.c  -	RIPE-MD160
+ *	Copyright (C) 1998 Free Software Foundation, Inc.
+ */
+
+/* This file was part of GnuPG. Modified for use within the Linux
+ * mount utility by Marc Mutz <Marc@Mutz.com>. None of this code is
+ * by myself. I just removed everything that you don't need when all
+ * you want to do is to use rmd160_hash_buffer().
+ * My comments are marked with (mm).  */
+
+/* GnuPG 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.
+ *
+ * GnuPG 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 <string.h> /* (mm) for memcpy */
+#include <endian.h> /* (mm) for BIG_ENDIAN and BYTE_ORDER */
+#include "rmd160.h"
+
+/* (mm) these are used by the original GnuPG file. In order to modify
+ * that file not too much, we keep the notations. maybe it would be
+ * better to include linux/types.h and typedef __u32 to u32 and __u8
+ * to byte?  */
+typedef unsigned int u32; /* taken from e.g. util-linux's minix.h */
+typedef unsigned char byte;
+
+typedef struct {
+    u32  h0,h1,h2,h3,h4;
+    u32  nblocks;
+    byte buf[64];
+    int  count;
+} RMD160_CONTEXT;
+
+/****************
+ * Rotate a 32 bit integer by n bytes
+ */
+#if defined(__GNUC__) && defined(__i386__)
+static inline u32
+rol( u32 x, int n)
+{
+	__asm__("roll %%cl,%0"
+		:"=r" (x)
+		:"0" (x),"c" (n));
+	return x;
+}
+#else
+  #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+/*********************************
+ * RIPEMD-160 is not patented, see (as of 25.10.97)
+ *   http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+ * Note that the code uses Little Endian byteorder, which is good for
+ * 386 etc, but we must add some conversion when used on a big endian box.
+ *
+ *
+ * Pseudo-code for RIPEMD-160
+ *
+ * RIPEMD-160 is an iterative hash function that operates on 32-bit words.
+ * The round function takes as input a 5-word chaining variable and a 16-word
+ * message block and maps this to a new chaining variable. All operations are
+ * defined on 32-bit words. Padding is identical to that of MD4.
+ *
+ *
+ * RIPEMD-160: definitions
+ *
+ *
+ *   nonlinear functions at bit level: exor, mux, -, mux, -
+ *
+ *   f(j, x, y, z) = x XOR y XOR z		  (0 <= j <= 15)
+ *   f(j, x, y, z) = (x AND y) OR (NOT(x) AND z)  (16 <= j <= 31)
+ *   f(j, x, y, z) = (x OR NOT(y)) XOR z	  (32 <= j <= 47)
+ *   f(j, x, y, z) = (x AND z) OR (y AND NOT(z))  (48 <= j <= 63)
+ *   f(j, x, y, z) = x XOR (y OR NOT(z))	  (64 <= j <= 79)
+ *
+ *
+ *   added constants (hexadecimal)
+ *
+ *   K(j) = 0x00000000	    (0 <= j <= 15)
+ *   K(j) = 0x5A827999	   (16 <= j <= 31)	int(2**30 x sqrt(2))
+ *   K(j) = 0x6ED9EBA1	   (32 <= j <= 47)	int(2**30 x sqrt(3))
+ *   K(j) = 0x8F1BBCDC	   (48 <= j <= 63)	int(2**30 x sqrt(5))
+ *   K(j) = 0xA953FD4E	   (64 <= j <= 79)	int(2**30 x sqrt(7))
+ *   K'(j) = 0x50A28BE6     (0 <= j <= 15)      int(2**30 x cbrt(2))
+ *   K'(j) = 0x5C4DD124    (16 <= j <= 31)      int(2**30 x cbrt(3))
+ *   K'(j) = 0x6D703EF3    (32 <= j <= 47)      int(2**30 x cbrt(5))
+ *   K'(j) = 0x7A6D76E9    (48 <= j <= 63)      int(2**30 x cbrt(7))
+ *   K'(j) = 0x00000000    (64 <= j <= 79)
+ *
+ *
+ *   selection of message word
+ *
+ *   r(j)      = j		      (0 <= j <= 15)
+ *   r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
+ *   r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
+ *   r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
+ *   r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+ *   r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
+ *   r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
+ *   r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
+ *   r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
+ *   r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+ *
+ *
+ *   amount for rotate left (rol)
+ *
+ *   s(0..15)  = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
+ *   s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
+ *   s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
+ *   s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
+ *   s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+ *   s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
+ *   s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
+ *   s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
+ *   s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
+ *   s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+ *
+ *
+ *   initial value (hexadecimal)
+ *
+ *   h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476;
+ *							h4 = 0xC3D2E1F0;
+ *
+ *
+ * RIPEMD-160: pseudo-code
+ *
+ *   It is assumed that the message after padding consists of t 16-word blocks
+ *   that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
+ *   The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
+ *   shift (rotate) over s positions.
+ *
+ *
+ *   for i := 0 to t-1 {
+ *	 A := h0; B := h1; C := h2; D = h3; E = h4;
+ *	 A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
+ *	 for j := 0 to 79 {
+ *	     T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
+ *	     A := E; E := D; D := rol_10(C); C := B; B := T;
+ *	     T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)]
+						       [+] K'(j)) [+] E';
+ *	     A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
+ *	 }
+ *	 T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
+ *	 h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
+ *   }
+ */
+
+/* Some examples:
+ * ""                    9c1185a5c5e9fc54612808977ee8f548b2258d31
+ * "a"                   0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
+ * "abc"                 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
+ * "message digest"      5d0689ef49d2fae572b881b123a85ffa21595f36
+ * "a...z"               f71c27109c692c1b56bbdceb5b9d2865b3708dbc
+ * "abcdbcde...nopq"     12a053384a9c0c88e405a06c27dcf49ada62eb2b
+ * "A...Za...z0...9"     b0e20b6e3116640286ed3a87a5713079b21f5189
+ * 8 times "1234567890"  9b752e45573d4b39f4dbd3323cab82bf63326bfb
+ * 1 million times "a"   52783243c1697bdbe16d37f97f68f08325dc1528
+ */
+
+
+static void
+rmd160_init( RMD160_CONTEXT *hd )
+{
+    hd->h0 = 0x67452301;
+    hd->h1 = 0xEFCDAB89;
+    hd->h2 = 0x98BADCFE;
+    hd->h3 = 0x10325476;
+    hd->h4 = 0xC3D2E1F0;
+    hd->nblocks = 0;
+    hd->count = 0;
+}
+
+
+
+/****************
+ * Transform the message X which consists of 16 32-bit-words
+ */
+static void
+transform( RMD160_CONTEXT *hd, byte *data )
+{
+    u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
+  #if BYTE_ORDER == BIG_ENDIAN
+    u32 x[16];
+    { int i;
+      byte *p2, *p1;
+      for(i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) {
+	p2[3] = *p1++;
+	p2[2] = *p1++;
+	p2[1] = *p1++;
+	p2[0] = *p1++;
+      }
+    }
+  #else
+   #if 0
+    u32 *x =(u32*)data;
+   #else
+    /* this version is better because it is always aligned;
+     * The performance penalty on a 586-100 is about 6% which
+     * is acceptable - because the data is more local it might
+     * also be possible that this is faster on some machines.
+     * This function (when compiled with -02 on gcc 2.7.2)
+     * executes on a 586-100 (39.73 bogomips) at about 1900kb/sec;
+     * [measured with a 4MB data and "gpgm --print-md rmd160"] */
+    u32 x[16];
+    memcpy( x, data, 64 );
+   #endif
+  #endif
+
+
+#define K0  0x00000000
+#define K1  0x5A827999
+#define K2  0x6ED9EBA1
+#define K3  0x8F1BBCDC
+#define K4  0xA953FD4E
+#define KK0 0x50A28BE6
+#define KK1 0x5C4DD124
+#define KK2 0x6D703EF3
+#define KK3 0x7A6D76E9
+#define KK4 0x00000000
+#define F0(x,y,z)   ( (x) ^ (y) ^ (z) )
+#define F1(x,y,z)   ( ((x) & (y)) | (~(x) & (z)) )
+#define F2(x,y,z)   ( ((x) | ~(y)) ^ (z) )
+#define F3(x,y,z)   ( ((x) & (z)) | ((y) & ~(z)) )
+#define F4(x,y,z)   ( (x) ^ ((y) | ~(z)) )
+#define R(a,b,c,d,e,f,k,r,s) do { t = a + f(b,c,d) + k + x[r]; \
+				  a = rol(t,s) + e;	       \
+				  c = rol(c,10);	       \
+				} while(0)
+
+    /* left lane */
+    a = hd->h0;
+    b = hd->h1;
+    c = hd->h2;
+    d = hd->h3;
+    e = hd->h4;
+    R( a, b, c, d, e, F0, K0,  0, 11 );
+    R( e, a, b, c, d, F0, K0,  1, 14 );
+    R( d, e, a, b, c, F0, K0,  2, 15 );
+    R( c, d, e, a, b, F0, K0,  3, 12 );
+    R( b, c, d, e, a, F0, K0,  4,  5 );
+    R( a, b, c, d, e, F0, K0,  5,  8 );
+    R( e, a, b, c, d, F0, K0,  6,  7 );
+    R( d, e, a, b, c, F0, K0,  7,  9 );
+    R( c, d, e, a, b, F0, K0,  8, 11 );
+    R( b, c, d, e, a, F0, K0,  9, 13 );
+    R( a, b, c, d, e, F0, K0, 10, 14 );
+    R( e, a, b, c, d, F0, K0, 11, 15 );
+    R( d, e, a, b, c, F0, K0, 12,  6 );
+    R( c, d, e, a, b, F0, K0, 13,  7 );
+    R( b, c, d, e, a, F0, K0, 14,  9 );
+    R( a, b, c, d, e, F0, K0, 15,  8 );
+    R( e, a, b, c, d, F1, K1,  7,  7 );
+    R( d, e, a, b, c, F1, K1,  4,  6 );
+    R( c, d, e, a, b, F1, K1, 13,  8 );
+    R( b, c, d, e, a, F1, K1,  1, 13 );
+    R( a, b, c, d, e, F1, K1, 10, 11 );
+    R( e, a, b, c, d, F1, K1,  6,  9 );
+    R( d, e, a, b, c, F1, K1, 15,  7 );
+    R( c, d, e, a, b, F1, K1,  3, 15 );
+    R( b, c, d, e, a, F1, K1, 12,  7 );
+    R( a, b, c, d, e, F1, K1,  0, 12 );
+    R( e, a, b, c, d, F1, K1,  9, 15 );
+    R( d, e, a, b, c, F1, K1,  5,  9 );
+    R( c, d, e, a, b, F1, K1,  2, 11 );
+    R( b, c, d, e, a, F1, K1, 14,  7 );
+    R( a, b, c, d, e, F1, K1, 11, 13 );
+    R( e, a, b, c, d, F1, K1,  8, 12 );
+    R( d, e, a, b, c, F2, K2,  3, 11 );
+    R( c, d, e, a, b, F2, K2, 10, 13 );
+    R( b, c, d, e, a, F2, K2, 14,  6 );
+    R( a, b, c, d, e, F2, K2,  4,  7 );
+    R( e, a, b, c, d, F2, K2,  9, 14 );
+    R( d, e, a, b, c, F2, K2, 15,  9 );
+    R( c, d, e, a, b, F2, K2,  8, 13 );
+    R( b, c, d, e, a, F2, K2,  1, 15 );
+    R( a, b, c, d, e, F2, K2,  2, 14 );
+    R( e, a, b, c, d, F2, K2,  7,  8 );
+    R( d, e, a, b, c, F2, K2,  0, 13 );
+    R( c, d, e, a, b, F2, K2,  6,  6 );
+    R( b, c, d, e, a, F2, K2, 13,  5 );
+    R( a, b, c, d, e, F2, K2, 11, 12 );
+    R( e, a, b, c, d, F2, K2,  5,  7 );
+    R( d, e, a, b, c, F2, K2, 12,  5 );
+    R( c, d, e, a, b, F3, K3,  1, 11 );
+    R( b, c, d, e, a, F3, K3,  9, 12 );
+    R( a, b, c, d, e, F3, K3, 11, 14 );
+    R( e, a, b, c, d, F3, K3, 10, 15 );
+    R( d, e, a, b, c, F3, K3,  0, 14 );
+    R( c, d, e, a, b, F3, K3,  8, 15 );
+    R( b, c, d, e, a, F3, K3, 12,  9 );
+    R( a, b, c, d, e, F3, K3,  4,  8 );
+    R( e, a, b, c, d, F3, K3, 13,  9 );
+    R( d, e, a, b, c, F3, K3,  3, 14 );
+    R( c, d, e, a, b, F3, K3,  7,  5 );
+    R( b, c, d, e, a, F3, K3, 15,  6 );
+    R( a, b, c, d, e, F3, K3, 14,  8 );
+    R( e, a, b, c, d, F3, K3,  5,  6 );
+    R( d, e, a, b, c, F3, K3,  6,  5 );
+    R( c, d, e, a, b, F3, K3,  2, 12 );
+    R( b, c, d, e, a, F4, K4,  4,  9 );
+    R( a, b, c, d, e, F4, K4,  0, 15 );
+    R( e, a, b, c, d, F4, K4,  5,  5 );
+    R( d, e, a, b, c, F4, K4,  9, 11 );
+    R( c, d, e, a, b, F4, K4,  7,  6 );
+    R( b, c, d, e, a, F4, K4, 12,  8 );
+    R( a, b, c, d, e, F4, K4,  2, 13 );
+    R( e, a, b, c, d, F4, K4, 10, 12 );
+    R( d, e, a, b, c, F4, K4, 14,  5 );
+    R( c, d, e, a, b, F4, K4,  1, 12 );
+    R( b, c, d, e, a, F4, K4,  3, 13 );
+    R( a, b, c, d, e, F4, K4,  8, 14 );
+    R( e, a, b, c, d, F4, K4, 11, 11 );
+    R( d, e, a, b, c, F4, K4,  6,  8 );
+    R( c, d, e, a, b, F4, K4, 15,  5 );
+    R( b, c, d, e, a, F4, K4, 13,  6 );
+
+    aa = a; bb = b; cc = c; dd = d; ee = e;
+
+    /* right lane */
+    a = hd->h0;
+    b = hd->h1;
+    c = hd->h2;
+    d = hd->h3;
+    e = hd->h4;
+    R( a, b, c, d, e, F4, KK0,	5,  8);
+    R( e, a, b, c, d, F4, KK0, 14,  9);
+    R( d, e, a, b, c, F4, KK0,	7,  9);
+    R( c, d, e, a, b, F4, KK0,	0, 11);
+    R( b, c, d, e, a, F4, KK0,	9, 13);
+    R( a, b, c, d, e, F4, KK0,	2, 15);
+    R( e, a, b, c, d, F4, KK0, 11, 15);
+    R( d, e, a, b, c, F4, KK0,	4,  5);
+    R( c, d, e, a, b, F4, KK0, 13,  7);
+    R( b, c, d, e, a, F4, KK0,	6,  7);
+    R( a, b, c, d, e, F4, KK0, 15,  8);
+    R( e, a, b, c, d, F4, KK0,	8, 11);
+    R( d, e, a, b, c, F4, KK0,	1, 14);
+    R( c, d, e, a, b, F4, KK0, 10, 14);
+    R( b, c, d, e, a, F4, KK0,	3, 12);
+    R( a, b, c, d, e, F4, KK0, 12,  6);
+    R( e, a, b, c, d, F3, KK1,	6,  9);
+    R( d, e, a, b, c, F3, KK1, 11, 13);
+    R( c, d, e, a, b, F3, KK1,	3, 15);
+    R( b, c, d, e, a, F3, KK1,	7,  7);
+    R( a, b, c, d, e, F3, KK1,	0, 12);
+    R( e, a, b, c, d, F3, KK1, 13,  8);
+    R( d, e, a, b, c, F3, KK1,	5,  9);
+    R( c, d, e, a, b, F3, KK1, 10, 11);
+    R( b, c, d, e, a, F3, KK1, 14,  7);
+    R( a, b, c, d, e, F3, KK1, 15,  7);
+    R( e, a, b, c, d, F3, KK1,	8, 12);
+    R( d, e, a, b, c, F3, KK1, 12,  7);
+    R( c, d, e, a, b, F3, KK1,	4,  6);
+    R( b, c, d, e, a, F3, KK1,	9, 15);
+    R( a, b, c, d, e, F3, KK1,	1, 13);
+    R( e, a, b, c, d, F3, KK1,	2, 11);
+    R( d, e, a, b, c, F2, KK2, 15,  9);
+    R( c, d, e, a, b, F2, KK2,	5,  7);
+    R( b, c, d, e, a, F2, KK2,	1, 15);
+    R( a, b, c, d, e, F2, KK2,	3, 11);
+    R( e, a, b, c, d, F2, KK2,	7,  8);
+    R( d, e, a, b, c, F2, KK2, 14,  6);
+    R( c, d, e, a, b, F2, KK2,	6,  6);
+    R( b, c, d, e, a, F2, KK2,	9, 14);
+    R( a, b, c, d, e, F2, KK2, 11, 12);
+    R( e, a, b, c, d, F2, KK2,	8, 13);
+    R( d, e, a, b, c, F2, KK2, 12,  5);
+    R( c, d, e, a, b, F2, KK2,	2, 14);
+    R( b, c, d, e, a, F2, KK2, 10, 13);
+    R( a, b, c, d, e, F2, KK2,	0, 13);
+    R( e, a, b, c, d, F2, KK2,	4,  7);
+    R( d, e, a, b, c, F2, KK2, 13,  5);
+    R( c, d, e, a, b, F1, KK3,	8, 15);
+    R( b, c, d, e, a, F1, KK3,	6,  5);
+    R( a, b, c, d, e, F1, KK3,	4,  8);
+    R( e, a, b, c, d, F1, KK3,	1, 11);
+    R( d, e, a, b, c, F1, KK3,	3, 14);
+    R( c, d, e, a, b, F1, KK3, 11, 14);
+    R( b, c, d, e, a, F1, KK3, 15,  6);
+    R( a, b, c, d, e, F1, KK3,	0, 14);
+    R( e, a, b, c, d, F1, KK3,	5,  6);
+    R( d, e, a, b, c, F1, KK3, 12,  9);
+    R( c, d, e, a, b, F1, KK3,	2, 12);
+    R( b, c, d, e, a, F1, KK3, 13,  9);
+    R( a, b, c, d, e, F1, KK3,	9, 12);
+    R( e, a, b, c, d, F1, KK3,	7,  5);
+    R( d, e, a, b, c, F1, KK3, 10, 15);
+    R( c, d, e, a, b, F1, KK3, 14,  8);
+    R( b, c, d, e, a, F0, KK4, 12,  8);
+    R( a, b, c, d, e, F0, KK4, 15,  5);
+    R( e, a, b, c, d, F0, KK4, 10, 12);
+    R( d, e, a, b, c, F0, KK4,	4,  9);
+    R( c, d, e, a, b, F0, KK4,	1, 12);
+    R( b, c, d, e, a, F0, KK4,	5,  5);
+    R( a, b, c, d, e, F0, KK4,	8, 14);
+    R( e, a, b, c, d, F0, KK4,	7,  6);
+    R( d, e, a, b, c, F0, KK4,	6,  8);
+    R( c, d, e, a, b, F0, KK4,	2, 13);
+    R( b, c, d, e, a, F0, KK4, 13,  6);
+    R( a, b, c, d, e, F0, KK4, 14,  5);
+    R( e, a, b, c, d, F0, KK4,	0, 15);
+    R( d, e, a, b, c, F0, KK4,	3, 13);
+    R( c, d, e, a, b, F0, KK4,	9, 11);
+    R( b, c, d, e, a, F0, KK4, 11, 11);
+
+
+    t	   = hd->h1 + d + cc;
+    hd->h1 = hd->h2 + e + dd;
+    hd->h2 = hd->h3 + a + ee;
+    hd->h3 = hd->h4 + b + aa;
+    hd->h4 = hd->h0 + c + bb;
+    hd->h0 = t;
+}
+
+
+/* Update the message digest with the contents
+ * of INBUF with length INLEN.
+ */
+static void
+rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
+{
+    if( hd->count == 64 ) { /* flush the buffer */
+	transform( hd, hd->buf );
+	hd->count = 0;
+	hd->nblocks++;
+    }
+    if( !inbuf )
+	return;
+    if( hd->count ) {
+	for( ; inlen && hd->count < 64; inlen-- )
+	    hd->buf[hd->count++] = *inbuf++;
+	rmd160_write( hd, NULL, 0 );
+	if( !inlen )
+	    return;
+    }
+
+    while( inlen >= 64 ) {
+	transform( hd, inbuf );
+	hd->count = 0;
+	hd->nblocks++;
+	inlen -= 64;
+	inbuf += 64;
+    }
+    for( ; inlen && hd->count < 64; inlen-- )
+	hd->buf[hd->count++] = *inbuf++;
+}
+
+/* The routine terminates the computation
+ */
+
+static void
+rmd160_final( RMD160_CONTEXT *hd )
+{
+    u32 t, msb, lsb;
+    byte *p;
+
+    rmd160_write(hd, NULL, 0); /* flush */;
+
+    msb = 0;
+    t = hd->nblocks;
+    if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
+	msb++;
+    msb += t >> 26;
+    t = lsb;
+    if( (lsb = t + hd->count) < t ) /* add the count */
+	msb++;
+    t = lsb;
+    if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
+	msb++;
+    msb += t >> 29;
+
+    if( hd->count < 56 ) { /* enough room */
+	hd->buf[hd->count++] = 0x80; /* pad */
+	while( hd->count < 56 )
+	    hd->buf[hd->count++] = 0;  /* pad */
+    }
+    else { /* need one extra block */
+	hd->buf[hd->count++] = 0x80; /* pad character */
+	while( hd->count < 64 )
+	    hd->buf[hd->count++] = 0;
+	rmd160_write(hd, NULL, 0);  /* flush */;
+	memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+    }
+    /* append the 64 bit count */
+    hd->buf[56] = lsb	   ;
+    hd->buf[57] = lsb >>  8;
+    hd->buf[58] = lsb >> 16;
+    hd->buf[59] = lsb >> 24;
+    hd->buf[60] = msb	   ;
+    hd->buf[61] = msb >>  8;
+    hd->buf[62] = msb >> 16;
+    hd->buf[63] = msb >> 24;
+    transform( hd, hd->buf );
+
+    p = hd->buf;
+  #if BYTE_ORDER == BIG_ENDIAN
+    #define X(a) do { *p++ = hd->h##a	   ; *p++ = hd->h##a >> 8;	\
+		      *p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0)
+  #else /* little endian */
+    #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+  #endif
+    X(0);
+    X(1);
+    X(2);
+    X(3);
+    X(4);
+  #undef X
+}
+
+/****************
+ * Shortcut functions which puts the hash value of the supplied buffer
+ * into outbuf which must have a size of 20 bytes.
+ */
+void
+rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length )
+{
+    RMD160_CONTEXT hd;
+
+    rmd160_init( &hd );
+    rmd160_write( &hd, (byte*)buffer, length );
+    rmd160_final( &hd );
+    memcpy( outbuf, hd.buf, 20 );
+}
diff -ru --new-file util-linux-2.11y/mount/rmd160.h util-linux-AES/mount/rmd160.h
--- util-linux-2.11y/mount/rmd160.h	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/rmd160.h	Mon Jan  6 21:59:33 2003
@@ -0,0 +1,9 @@
+#ifndef RMD160_H
+#define RMD160_H
+
+#define RMD160_HASH_SIZE 20
+
+void
+rmd160_hash_buffer (char *outbuf, const char *buffer, size_t length);
+
+#endif /*RMD160_H*/
diff -ru --new-file util-linux-2.11y/mount/sha512.c util-linux-AES/mount/sha512.c
--- util-linux-2.11y/mount/sha512.c	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/sha512.c	Mon Jan  6 21:59:33 2003
@@ -0,0 +1,432 @@
+/*
+ *  sha512.c
+ *
+ *  Written by Jari Ruusu, April 16 2001
+ *
+ *  Copyright 2001 by Jari Ruusu.
+ *  Redistribution of this file is permitted under the GNU Public License.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include "sha512.h"
+
+/* Define one or more of these. If none is defined, you get all of them */
+#if !defined(SHA256_NEEDED)&&!defined(SHA512_NEEDED)&&!defined(SHA384_NEEDED)
+# define SHA256_NEEDED  1
+# define SHA512_NEEDED  1
+# define SHA384_NEEDED  1
+#endif
+
+#if defined(SHA256_NEEDED)
+static const u_int32_t sha256_hashInit[8] = {
+    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
+    0x1f83d9ab, 0x5be0cd19
+};
+static const u_int32_t sha256_K[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+    0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+    0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+    0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+#endif
+
+#if defined(SHA512_NEEDED)
+static const u_int64_t sha512_hashInit[8] = {
+    0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
+    0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+    0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
+};
+#endif
+
+#if defined(SHA384_NEEDED)
+static const u_int64_t sha384_hashInit[8] = {
+    0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL,
+    0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
+    0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL
+};
+#endif
+
+#if defined(SHA512_NEEDED) || defined(SHA384_NEEDED)
+static const u_int64_t sha512_K[80] = {
+    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+    0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+    0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+    0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+    0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+    0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+    0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+    0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+    0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+    0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+    0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+    0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+    0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+    0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+#endif
+
+#define Ch(x,y,z)   (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z)  (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define R(x,y)      ((y) >> (x))
+
+#if defined(SHA256_NEEDED)
+void sha256_init(sha256_context *ctx)
+{
+    memcpy(&ctx->sha_H[0], &sha256_hashInit[0], sizeof(ctx->sha_H));
+    ctx->sha_blocks = 0;
+    ctx->sha_bufCnt = 0;
+}
+
+#define S(x,y)      (((y) >> (x)) | ((y) << (32 - (x))))
+#define uSig0(x)    ((S(2,(x))) ^ (S(13,(x))) ^ (S(22,(x))))
+#define uSig1(x)    ((S(6,(x))) ^ (S(11,(x))) ^ (S(25,(x))))
+#define lSig0(x)    ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x))))
+#define lSig1(x)    ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x))))
+
+static void sha256_transform(sha256_context *ctx, unsigned char *datap)
+{
+    register int    j;
+    u_int32_t       a, b, c, d, e, f, g, h;
+    u_int32_t       T1, T2, W[64], Wm2, Wm15;
+
+    /* read the data, big endian byte order */
+    j = 0;
+    do {
+        W[j] = (((u_int32_t)(datap[0]))<<24) | (((u_int32_t)(datap[1]))<<16) |
+               (((u_int32_t)(datap[2]))<<8 ) | ((u_int32_t)(datap[3]));
+        datap += 4;
+    } while(++j < 16);
+    
+    /* initialize variables a...h */
+    a = ctx->sha_H[0];
+    b = ctx->sha_H[1];
+    c = ctx->sha_H[2];
+    d = ctx->sha_H[3];
+    e = ctx->sha_H[4];
+    f = ctx->sha_H[5];
+    g = ctx->sha_H[6];
+    h = ctx->sha_H[7];
+
+    /* apply compression function */
+    j = 0;
+    do {
+        if(j >= 16) {
+            Wm2 = W[j - 2];
+            Wm15 = W[j - 15];
+            W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+        }
+        T1 = h + uSig1(e) + Ch(e,f,g) + sha256_K[j] + W[j];
+        T2 = uSig0(a) + Maj(a,b,c);
+        h = g; g = f; f = e;
+        e = d + T1;
+        d = c; c = b; b = a;
+        a = T1 + T2;
+    } while(++j < 64);
+
+    /* compute intermediate hash value */
+    ctx->sha_H[0] += a;
+    ctx->sha_H[1] += b;
+    ctx->sha_H[2] += c;
+    ctx->sha_H[3] += d;
+    ctx->sha_H[4] += e;
+    ctx->sha_H[5] += f;
+    ctx->sha_H[6] += g;
+    ctx->sha_H[7] += h;
+
+    ctx->sha_blocks++;
+}
+
+void sha256_write(sha256_context *ctx, unsigned char *datap, int length)
+{
+    while(length > 0) {
+        if(!ctx->sha_bufCnt) {
+            while(length >= sizeof(ctx->sha_out)) {
+                sha256_transform(ctx, datap);
+                datap += sizeof(ctx->sha_out);
+                length -= sizeof(ctx->sha_out);
+            }
+            if(!length) return;
+        }
+        ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+        length--;
+        if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) {
+            sha256_transform(ctx, &ctx->sha_out[0]);
+            ctx->sha_bufCnt = 0;
+        }
+    }
+}
+
+void sha256_final(sha256_context *ctx)
+{
+    register int    j;
+    u_int64_t       bitLength;
+    u_int32_t       i;
+    unsigned char   padByte, *datap;
+
+    bitLength = (ctx->sha_blocks << 9) | (ctx->sha_bufCnt << 3);
+    padByte = 0x80;
+    sha256_write(ctx, &padByte, 1);
+
+    /* pad extra space with zeroes */
+    padByte = 0;
+    while(ctx->sha_bufCnt != 56) {
+        sha256_write(ctx, &padByte, 1);
+    }
+
+    /* write bit length, big endian byte order */
+    ctx->sha_out[56] = bitLength >> 56;
+    ctx->sha_out[57] = bitLength >> 48;
+    ctx->sha_out[58] = bitLength >> 40;
+    ctx->sha_out[59] = bitLength >> 32;
+    ctx->sha_out[60] = bitLength >> 24;
+    ctx->sha_out[61] = bitLength >> 16;
+    ctx->sha_out[62] = bitLength >> 8;
+    ctx->sha_out[63] = bitLength;
+    sha256_transform(ctx, &ctx->sha_out[0]);
+    
+    /* return results in ctx->sha_out[0...31] */
+    datap = &ctx->sha_out[0];
+    j = 0;
+    do {
+        i = ctx->sha_H[j];
+        datap[0] = i >> 24;
+        datap[1] = i >> 16;
+        datap[2] = i >> 8;
+        datap[3] = i;
+        datap += 4;
+    } while(++j < 8);
+
+    /* clear sensitive information */
+    memset(&ctx->sha_out[32], 0, sizeof(sha256_context) - 32);
+}
+
+void sha256_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+    sha256_context ctx;
+
+    if(ole < 1) return;
+    memset(ob, 0, ole);
+    if(ole > 32) ole = 32;
+    sha256_init(&ctx);
+    sha256_write(&ctx, ib, ile);
+    sha256_final(&ctx);
+    memcpy(ob, &ctx.sha_out[0], ole);
+    memset(&ctx, 0, sizeof(ctx));
+}
+
+#endif
+
+#if defined(SHA512_NEEDED)
+void sha512_init(sha512_context *ctx)
+{
+    memcpy(&ctx->sha_H[0], &sha512_hashInit[0], sizeof(ctx->sha_H));
+    ctx->sha_blocks = 0;
+    ctx->sha_blocksMSB = 0;
+    ctx->sha_bufCnt = 0;
+}
+#endif
+
+#if defined(SHA512_NEEDED) || defined(SHA384_NEEDED)
+#undef S
+#undef uSig0
+#undef uSig1
+#undef lSig0
+#undef lSig1
+#define S(x,y)      (((y) >> (x)) | ((y) << (64 - (x))))
+#define uSig0(x)    ((S(28,(x))) ^ (S(34,(x))) ^ (S(39,(x))))
+#define uSig1(x)    ((S(14,(x))) ^ (S(18,(x))) ^ (S(41,(x))))
+#define lSig0(x)    ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x))))
+#define lSig1(x)    ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x))))
+
+static void sha512_transform(sha512_context *ctx, unsigned char *datap)
+{
+    register int    j;
+    u_int64_t       a, b, c, d, e, f, g, h;
+    u_int64_t       T1, T2, W[80], Wm2, Wm15;
+
+    /* read the data, big endian byte order */
+    j = 0;
+    do {
+        W[j] = (((u_int64_t)(datap[0]))<<56) | (((u_int64_t)(datap[1]))<<48) |
+               (((u_int64_t)(datap[2]))<<40) | (((u_int64_t)(datap[3]))<<32) |
+               (((u_int64_t)(datap[4]))<<24) | (((u_int64_t)(datap[5]))<<16) |
+               (((u_int64_t)(datap[6]))<<8 ) | ((u_int64_t)(datap[7]));
+        datap += 8;
+    } while(++j < 16);
+    
+    /* initialize variables a...h */
+    a = ctx->sha_H[0];
+    b = ctx->sha_H[1];
+    c = ctx->sha_H[2];
+    d = ctx->sha_H[3];
+    e = ctx->sha_H[4];
+    f = ctx->sha_H[5];
+    g = ctx->sha_H[6];
+    h = ctx->sha_H[7];
+
+    /* apply compression function */
+    j = 0;
+    do {
+        if(j >= 16) {
+            Wm2 = W[j - 2];
+            Wm15 = W[j - 15];
+            W[j] = lSig1(Wm2) + W[j - 7] + lSig0(Wm15) + W[j - 16];
+        }
+        T1 = h + uSig1(e) + Ch(e,f,g) + sha512_K[j] + W[j];
+        T2 = uSig0(a) + Maj(a,b,c);
+        h = g; g = f; f = e;
+        e = d + T1;
+        d = c; c = b; b = a;
+        a = T1 + T2;
+    } while(++j < 80);
+
+    /* compute intermediate hash value */
+    ctx->sha_H[0] += a;
+    ctx->sha_H[1] += b;
+    ctx->sha_H[2] += c;
+    ctx->sha_H[3] += d;
+    ctx->sha_H[4] += e;
+    ctx->sha_H[5] += f;
+    ctx->sha_H[6] += g;
+    ctx->sha_H[7] += h;
+
+    ctx->sha_blocks++;
+    if(!ctx->sha_blocks) ctx->sha_blocksMSB++;
+}
+
+void sha512_write(sha512_context *ctx, unsigned char *datap, int length)
+{
+    while(length > 0) {
+        if(!ctx->sha_bufCnt) {
+            while(length >= sizeof(ctx->sha_out)) {
+                sha512_transform(ctx, datap);
+                datap += sizeof(ctx->sha_out);
+                length -= sizeof(ctx->sha_out);
+            }
+            if(!length) return;
+        }
+        ctx->sha_out[ctx->sha_bufCnt] = *datap++;
+        length--;
+        if(++ctx->sha_bufCnt == sizeof(ctx->sha_out)) {
+            sha512_transform(ctx, &ctx->sha_out[0]);
+            ctx->sha_bufCnt = 0;
+        }
+    }
+}
+
+void sha512_final(sha512_context *ctx)
+{
+    register int    j;
+    u_int64_t       bitLength, bitLengthMSB;
+    u_int64_t       i;
+    unsigned char   padByte, *datap;
+
+    bitLength = (ctx->sha_blocks << 10) | (ctx->sha_bufCnt << 3);
+    bitLengthMSB = (ctx->sha_blocksMSB << 10) | (ctx->sha_blocks >> 54);
+    padByte = 0x80;
+    sha512_write(ctx, &padByte, 1);
+
+    /* pad extra space with zeroes */
+    padByte = 0;
+    while(ctx->sha_bufCnt != 112) {
+        sha512_write(ctx, &padByte, 1);
+    }
+
+    /* write bit length, big endian byte order */
+    ctx->sha_out[112] = bitLengthMSB >> 56;
+    ctx->sha_out[113] = bitLengthMSB >> 48;
+    ctx->sha_out[114] = bitLengthMSB >> 40;
+    ctx->sha_out[115] = bitLengthMSB >> 32;
+    ctx->sha_out[116] = bitLengthMSB >> 24;
+    ctx->sha_out[117] = bitLengthMSB >> 16;
+    ctx->sha_out[118] = bitLengthMSB >> 8;
+    ctx->sha_out[119] = bitLengthMSB;
+    ctx->sha_out[120] = bitLength >> 56;
+    ctx->sha_out[121] = bitLength >> 48;
+    ctx->sha_out[122] = bitLength >> 40;
+    ctx->sha_out[123] = bitLength >> 32;
+    ctx->sha_out[124] = bitLength >> 24;
+    ctx->sha_out[125] = bitLength >> 16;
+    ctx->sha_out[126] = bitLength >> 8;
+    ctx->sha_out[127] = bitLength;
+    sha512_transform(ctx, &ctx->sha_out[0]);
+    
+    /* return results in ctx->sha_out[0...63] */
+    datap = &ctx->sha_out[0];
+    j = 0;
+    do {
+        i = ctx->sha_H[j];
+        datap[0] = i >> 56;
+        datap[1] = i >> 48;
+        datap[2] = i >> 40;
+        datap[3] = i >> 32;
+        datap[4] = i >> 24;
+        datap[5] = i >> 16;
+        datap[6] = i >> 8;
+        datap[7] = i;
+        datap += 8;
+    } while(++j < 8);
+
+    /* clear sensitive information */
+    memset(&ctx->sha_out[64], 0, sizeof(sha512_context) - 64);
+}
+
+void sha512_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+    sha512_context ctx;
+
+    if(ole < 1) return;
+    memset(ob, 0, ole);
+    if(ole > 64) ole = 64;
+    sha512_init(&ctx);
+    sha512_write(&ctx, ib, ile);
+    sha512_final(&ctx);
+    memcpy(ob, &ctx.sha_out[0], ole);
+    memset(&ctx, 0, sizeof(ctx));
+}
+#endif
+
+#if defined(SHA384_NEEDED)
+void sha384_init(sha512_context *ctx)
+{
+    memcpy(&ctx->sha_H[0], &sha384_hashInit[0], sizeof(ctx->sha_H));
+    ctx->sha_blocks = 0;
+    ctx->sha_blocksMSB = 0;
+    ctx->sha_bufCnt = 0;
+}
+
+void sha384_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole)
+{
+    sha512_context ctx;
+
+    if(ole < 1) return;
+    memset(ob, 0, ole);
+    if(ole > 48) ole = 48;
+    sha384_init(&ctx);
+    sha512_write(&ctx, ib, ile);
+    sha512_final(&ctx);
+    memcpy(ob, &ctx.sha_out[0], ole);
+    memset(&ctx, 0, sizeof(ctx));
+}
+#endif
diff -ru --new-file util-linux-2.11y/mount/sha512.h util-linux-AES/mount/sha512.h
--- util-linux-2.11y/mount/sha512.h	Thu Jan  1 01:00:00 1970
+++ util-linux-AES/mount/sha512.h	Mon Jan  6 21:59:33 2003
@@ -0,0 +1,45 @@
+/*
+ *  sha512.h
+ *
+ *  Written by Jari Ruusu, April 16 2001
+ *
+ *  Copyright 2001 by Jari Ruusu.
+ *  Redistribution of this file is permitted under the GNU Public License.
+ */
+
+#include <sys/types.h>
+
+typedef struct {
+    unsigned char   sha_out[64];    /* results are here, bytes 0...31 */
+    u_int32_t       sha_H[8];
+    u_int64_t       sha_blocks;
+    int             sha_bufCnt;
+} sha256_context;
+
+typedef struct {
+    unsigned char   sha_out[128];   /* results are here, bytes 0...63 */
+    u_int64_t       sha_H[8];
+    u_int64_t       sha_blocks;
+    u_int64_t       sha_blocksMSB;
+    int             sha_bufCnt;
+} sha512_context;
+
+/* no sha384_context, use sha512_context */
+
+/* 256 bit hash, provides 128 bits of security against collision attacks */
+extern void sha256_init(sha256_context *);
+extern void sha256_write(sha256_context *, unsigned char *, int);
+extern void sha256_final(sha256_context *);
+extern void sha256_hash_buffer(unsigned char *, int, unsigned char *, int);
+
+/* 512 bit hash, provides 256 bits of security against collision attacks */
+extern void sha512_init(sha512_context *);
+extern void sha512_write(sha512_context *, unsigned char *, int);
+extern void sha512_final(sha512_context *);
+extern void sha512_hash_buffer(unsigned char *, int, unsigned char *, int);
+
+/* 384 bit hash, provides 192 bits of security against collision attacks */
+extern void sha384_init(sha512_context *);
+/* no sha384_write(), use sha512_write() */
+/* no sha384_final(), use sha512_final(), result in ctx->sha_out[0...47]  */
+extern void sha384_hash_buffer(unsigned char *, int, unsigned char *, int);
diff -ru --new-file util-linux-2.11y/mount/sundries.c util-linux-AES/mount/sundries.c
--- util-linux-2.11y/mount/sundries.c	Fri Nov  1 02:00:50 2002
+++ util-linux-AES/mount/sundries.c	Wed Feb  5 15:21:36 2003
@@ -162,7 +162,7 @@
 	  return 1;
 
      no = 0;
-     if (!strncmp(types, "no", 2)) {
+     if (types && !strncmp(types, "no", 2)) {
 	  no = 1;
 	  types += 2;
      }
diff -ru --new-file util-linux-2.11y/mount/swapon.8 util-linux-AES/mount/swapon.8
--- util-linux-2.11y/mount/swapon.8	Thu Oct 31 19:00:03 2002
+++ util-linux-AES/mount/swapon.8	Fri Feb  7 12:37:56 2003
@@ -117,6 +117,20 @@
 .I /proc/swaps
 or
 .IR /etc/fstab ).
+.PP
+If
+.I loop=/dev/loop?
+and
+.I encryption=AES128
+options are present in
+.I /etc/fstab
+then
+.BR "swapon -a"
+will set up loop devices using random keys, run
+.BR "mkswap"
+on them, and enable encrypted swap on specified loop devices.
+.BR "swapoff -a"
+will tear down such loop devices.
 .SH NOTE
 You should not use
 .B swapon
diff -ru --new-file util-linux-2.11y/mount/swapon.c util-linux-AES/mount/swapon.c
--- util-linux-2.11y/mount/swapon.c	Fri Nov  1 01:38:49 2002
+++ util-linux-AES/mount/swapon.c	Fri Feb  7 12:37:56 2003
@@ -11,19 +11,29 @@
  * 2001-03-22 Erik Troan <ewt@redhat.com>
  * - added -e option for -a
  * - -a shouldn't try to add swaps that are already enabled
+ * 2002-04-14 Jari Ruusu <jari.ruusu@pp.inet.fi>
+ * - added encrypted swap support
  */
 
 #include <ctype.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <getopt.h>
 #include <string.h>
 #include <mntent.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
 #include "swap_constants.h"
 #include "swapargs.h"
 #include "nls.h"
+#include "loop.h"
+#include "sha512.h"
 
 #define streq(s, t)	(strcmp ((s), (t)) == 0)
 
@@ -258,6 +268,263 @@
 }
 
 static int
+prepare_encrypted_swap(char *partition, char *loop, char *encryption)
+{
+	int x, y, z, pfd[2];
+	sha512_context s;
+	unsigned char b[4096];
+	char *a[8];
+	FILE *f;
+	struct loop_info loopinfo;
+
+	/*
+	 * Some sanity checks
+	 */
+	if(strlen(partition) < 1) {
+		fprintf(stderr, _("swapon: invalid swap device name\n"));
+		return 0;
+	}
+	if(strlen(loop) < 1) {
+		fprintf(stderr, _("swapon: invalid loop device name\n"));
+		return 0;
+	}
+	if(strlen(encryption) < 1) {
+		fprintf(stderr, _("swapon: invalid encryption type\n"));
+		return 0;
+	}
+
+	/*
+	 * Abort if loop device does not exist or is already in use
+	 */
+	if((x = open(loop, O_RDONLY)) == -1) {
+		fprintf(stderr, _("swapon: unable to open loop device %s\n"), loop);
+		return 0;
+	}
+	if(ioctl(x, LOOP_GET_STATUS, &loopinfo) == 0) {
+		fprintf(stderr, _("swapon: loop device %s already in use\n"), loop);
+		close(x);
+		return 0;
+	}
+	close(x);
+
+	/*
+	 * Compute SHA-512 over first 40 KB of old swap data. This data
+	 * is mostly unknown data encrypted using unknown key. SHA-512 hash
+	 * output is then used as entropy for new swap encryption key.
+	 */
+	if(!(f = fopen(partition, "r+"))) {
+		fprintf(stderr, _("swapon: unable to open swap device %s\n"), partition);
+		return 0;
+	}
+	sha512_init(&s);
+	for(x = 0; x < 10; x++) {
+		if(fread(&b[0], sizeof(b), 1, f) != 1) break;
+		sha512_write(&s, &b[0], sizeof(b));
+	}
+	sha512_final(&s);
+
+	/*
+	 * Overwrite 40 KB of old swap data 20 times so that recovering
+	 * SHA-512 output beyond this point is difficult and expensive.
+	 */
+	memset(&b[0], 0, sizeof(b));
+	for(y = 0; y < 20; y++) {
+		fseek(f, 0L, SEEK_SET);
+		for(x = 0; x < 10; x++) {
+			if(fwrite(&b[0], sizeof(b), 1, f) != 1) break;
+		}
+		if(fflush(f)) break;
+		if(fsync(fileno(f))) break;
+	}
+	fclose(f);
+
+	/*
+	 * Use all 512 bits of hash output
+	 */
+	memcpy(&b[0], &s.sha_out[0], 64);
+	memset(&s, 0, sizeof(s));
+
+	/*
+	 * Read 32 bytes of random entropy from kernel's random
+	 * number generator. This code may be executed early on startup
+	 * scripts and amount of random entropy may be non-existent.
+	 * SHA-512 of old swap data is used as workaround for missing
+	 * entropy in kernel's random number generator.
+	 */
+	if(!(f = fopen("/dev/urandom", "r"))) {
+		fprintf(stderr, _("swapon: unable to open /dev/urandom\n"));
+		return 0;
+	}
+	fread(&b[64], 32, 1, f);
+	fclose(f);
+
+	/*
+	 * Encode random password to use printable characters A-Z a-z 0-9 . /
+	 */
+	for(y = x = 0; x < ((64 + 32) * 8); x += 6, y++) {
+		z = (int)(b[x >> 3]) >> (x & 7);
+		z |= (int)(b[(x >> 3) + 1]) << (8 - (x & 7));
+		z &= 63;
+		if(z < 26) {
+			z += 'A';
+		} else if(z < 52) {
+			z += 'a' - 26;
+		} else if(z < 62) {
+			z += '0' - 52;
+		} else if(z == 62) {
+			z = '.';
+		} else {
+			z = '/';
+		}
+		b[y + 128] = z;
+		b[y + 128 + 1] = '\n';
+		b[y + 128 + 2] = 0;
+	}
+
+	/*
+	 * Run losetup and feed password through a pipe
+	 */
+	if(pipe(&pfd[0])) {
+		fprintf(stderr, _("swapon: unable to create pipe\n"));
+		return 0;
+	}
+	sprintf(&b[0], "%d", pfd[0]);
+	if(!(x = fork())) {
+		close(pfd[1]);  
+		a[0] = "losetup";
+		a[1] = "-p";
+		a[2] = &b[0];
+		a[3] = "-e";
+		a[4] = encryption;
+		a[5] = loop;
+		a[6] = partition;
+		a[7] = 0;
+		execvp(a[0], &a[0]);
+		execv("/sbin/losetup", &a[0]);
+		fprintf(stderr, _("swapon: unable to execute losetup\n"));
+		exit(1);
+	}
+	close(pfd[0]);  
+	if(x == -1) {
+		fprintf(stderr, _("swapon: fork failed\n"));
+		close(pfd[1]);  
+		return 0;
+	}
+	write(pfd[1], &b[128], strlen(&b[128]));
+	close(pfd[1]);  
+	waitpid(x, &y, 0);
+	if(!WIFEXITED(y) || (WEXITSTATUS(y) != 0)) {
+		fprintf(stderr, _("swapon: losetup failed to initialize %s\n"), loop);
+		return 0;
+	}
+
+	/* use -v option to display this */
+	if(verbose) {
+		printf(_("swapon: random password for %s is %s"), loop, &b[128]);
+	}
+
+	/*
+	 * Write 40 KB of zeroes to loop device. That same data is written
+	 * to underlying partition in encrypted form. This is done to guarantee
+	 * that next time encrypted swap is initialized, the SHA-512 hash will
+	 * be different. And, if encrypted swap data writes over this data, that's
+	 * even better.
+	 */
+	if(!(f = fopen(loop, "r+"))) {
+		fprintf(stderr, _("swapon: unable to open loop device %s\n"), loop);
+		return 0;
+	}
+	memset(&b[0], 0, sizeof(b));
+	for(x = 0; x < 10; x++) {
+		if(fwrite(&b[0], sizeof(b), 1, f) != 1) break;
+	}
+	fflush(f);
+	fsync(fileno(f));
+	fclose(f);
+	sync();
+
+	/*
+	 * Run mkswap on loop device so that kernel understands it as swap.
+	 * Redirect stderr to /dev/null and ignore exit value.
+	 */
+	if(!(x = fork())) {
+		int kver = 0, kpat = 0;
+		struct utsname un;
+
+		/* detect running kernel version */
+		y = 0;
+		if(uname(&un) == 0) {
+			sscanf(&un.release[0], "%d.%d", &kver, &kpat);
+			y = (kver * 65536) + (kpat * 256);
+		}
+
+		if((x = open("/dev/null", O_WRONLY)) >= 0) {
+			dup2(x, 2);
+			close(x);
+		}
+		x = 0;
+		a[x++] = "mkswap";
+		if(y >= 0x20500) {
+			/* some 2.5 kernels don't understand type 0 swap partitions */ 
+			a[x++] = "-v1";
+		}
+		a[x++] = loop;
+		a[x] = 0;
+		execvp(a[0], &a[0]);
+		execv("/sbin/mkswap", &a[0]);
+		/* error to stdout, stderr is directed to /dev/null */
+		printf(_("swapon: unable to execute mkswap\n"));
+		exit(1);
+	}
+	if(x == -1) {
+		fprintf(stderr, _("swapon: fork failed\n"));
+		return 0;
+	}
+	waitpid(x, &y, 0);
+	sync();
+
+	return 1;
+}
+
+static void
+shutdown_encrypted_swap(char *loop)
+{
+	int fd;
+	struct stat statbuf;
+	struct loop_info loopinfo;
+	unsigned char b[32];
+	FILE *f;
+
+	if(stat(loop, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+		if((fd = open(loop, O_RDWR)) >= 0) {
+			if(!ioctl(fd, LOOP_GET_STATUS, &loopinfo)) {
+				/*
+				 * Read 32 bytes of random data from kernel's random
+				 * number generator and write that to loop device.
+				 * This preserves some of kernel's random entropy
+				 * to next activation of encrypted swap on this
+				 * partition.
+				 */
+				if((f = fopen("/dev/urandom", "r")) != NULL) {
+					fread(&b[0], 32, 1, f);
+					fclose(f);
+					write(fd, &b[0], 32);
+					fsync(fd);
+				}
+			}
+			close(fd);
+		}
+		sync();
+		if((fd = open(loop, O_RDONLY)) >= 0) {
+			if(!ioctl(fd, LOOP_GET_STATUS, &loopinfo)) {
+				ioctl(fd, LOOP_CLR_FD, 0);
+			}
+			close(fd);
+		}
+	}
+}
+
+static int
 main_swapon(int argc, char *argv[]) {
 	FILE *fp;
 	struct mntent *fstab;
@@ -316,17 +583,32 @@
 		while ((fstab = getmntent(fp)) != NULL) {
 			char *special = fstab->mnt_fsname;
 
-			if (streq(fstab->mnt_type, MNTTYPE_SWAP) &&
-			    !is_in_proc_swaps(special)
-			    && (!ifexists || !access(special, R_OK))) {
+			if (streq(fstab->mnt_type, MNTTYPE_SWAP)) {
 				/* parse mount options; */
 				char *opt, *opts = strdup(fstab->mnt_opts);
-	   
-				for (opt = strtok(opts, ","); opt != NULL;
-				     opt = strtok(NULL, ","))
+				char *loop = NULL, *encryption = NULL;
+
+				for (opt = strtok(opts, ","); opt != NULL; opt = strtok(NULL, ",")) {
 					if (strncmp(opt, "pri=", 4) == 0)
 						priority = atoi(opt+4);
-				status |= do_swapon(special, priority);
+					if (strncmp(opt, "loop=", 5) == 0)
+						loop = opt + 5;
+					if (strncmp(opt, "encryption=", 11) == 0)
+						encryption = opt + 11;
+				}
+				if (loop && encryption) {
+					if(!is_in_proc_swaps(loop) && (!ifexists || !access(special, R_OK))) {
+						if (!prepare_encrypted_swap(special, loop, encryption)) {
+							status |= -1;
+							continue;
+						}
+						status |= do_swapon(loop, priority);
+					}
+					continue;
+				}
+				if (!is_in_proc_swaps(special) && (!ifexists || !access(special, R_OK))) {
+					status |= do_swapon(special, priority);
+				}
 			}
 		}
 	}
@@ -403,9 +685,27 @@
 			exit(2);
 		}
 		while ((fstab = getmntent(fp)) != NULL) {
-			if (streq(fstab->mnt_type, MNTTYPE_SWAP) &&
-			    !is_in_proc_swaps(fstab->mnt_fsname))
-				do_swapoff(fstab->mnt_fsname, QUIET);
+			if (streq(fstab->mnt_type, MNTTYPE_SWAP)) {
+				/* parse mount options; */
+				char *opt, *opts = strdup(fstab->mnt_opts);
+				char *loop = NULL, *encryption = NULL;
+
+				for (opt = strtok(opts, ","); opt != NULL; opt = strtok(NULL, ",")) {
+					if (strncmp(opt, "loop=", 5) == 0)
+						loop = opt + 5;
+					if (strncmp(opt, "encryption=", 11) == 0)
+						encryption = opt + 11;
+				}
+				if (loop && encryption) {
+					if (!is_in_proc_swaps(loop))
+						do_swapoff(loop, QUIET);
+					shutdown_encrypted_swap(loop);
+					continue;
+				}
+				if (!is_in_proc_swaps(fstab->mnt_fsname)) {
+					do_swapoff(fstab->mnt_fsname, QUIET);
+				}
+			}
 		}
 	}
 
