--- util-linux-2.12.orig/mount/Makefile +++ util-linux-2.12/mount/Makefile @@ -24,7 +26,7 @@ MAYBE = pivot_root swapoff -LO_OBJS = lomount.o $(LIB)/xstrncpy.o +LO_OBJS = lomount.o $(LIB)/xstrncpy.o rmd160.o NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o GEN_FILES = nfsmount.h nfsmount_xdr.c nfsmount_clnt.c @@ -57,7 +59,7 @@ main_losetup.o: lomount.c $(COMPILE) -DMAIN lomount.c -o $@ -losetup: main_losetup.o $(LIB)/xstrncpy.o +losetup: main_losetup.o $(LIB)/xstrncpy.o rmd160.o $(LINK) $^ -o $@ mount.o umount.o nfsmount.o losetup.o fstab.o realpath.o sundries.o: sundries.h --- util-linux-2.12/mount/lomount.c.orig 2003-07-17 01:56:53.000000000 +0200 +++ util-linux-2.12/mount/lomount.c 2004-08-04 19:27:23.000000000 +0200 @@ -33,15 +33,80 @@ #include "loop.h" #include "lomount.h" +#include "rmd160.h" #include "xstrncpy.h" #include "nls.h" extern int verbose; -extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ +extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ extern void error (const char *fmt, ...); /* idem */ #ifdef LOOP_SET_FD +#include +#include + +struct crypt_type_struct { + int id; + char *name; + int keylength; +} crypt_type_tbl[] = { + { LO_CRYPT_NONE, "none", 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 struct option longopts[] = { + { "delete", 0, 0, 'd' }, + { "detach", 0, 0, 'd' }, + { "encryption", 1, 0, 'e' }, + { "help", 0, 0, 'h' }, + { "nopasshash", 1, 0, 'N' }, + { "offset", 1, 0, 'o' }, + { "pass-fd", 1, 0, 'p' }, + { "verbose", 0, 0, 'v' }, + { "keybits", 1, 0, 'k' }, + { NULL, 0, 0, 0 } +}; + +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 + + static int loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) { @@ -126,7 +191,8 @@ printf(_(", offset %d"), loopinfo.lo_offset); if (loopinfo.lo_encrypt_type) - printf(_(", encryption type %d\n"), + printf(_(", encryption %s (type %d)\n"), + id_to_name(loopinfo.lo_encrypt_type), loopinfo.lo_encrypt_type); printf("\n"); @@ -189,10 +255,9 @@ error(_("mount: could not find any device /dev/loop#")); else if (!someloop) { error(_( - "mount: Could not find any loop device. Maybe this kernel " - "does not know\n" - " about the loop device? (If so, recompile or " - "`modprobe loop'.)")); + "mount: Could not find any loop device. Maybe this kernel does not know\n" + " about the loop device? (If so, 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; @@ -247,10 +312,20 @@ int set_loop(const char *device, const char *file, int offset, - const char *encryption, int pfd, int *loopro) { + const char *encryption, int pfd, int keysz, int *loopro, int hash_password) { struct loop_info64 loopinfo64; int fd, ffd, mode; char *pass; + int tried_old; + + int kerneli=open("/proc/crypto/cipher",O_RDONLY); + + if (kerneli>=0) { + close(kerneli); + kerneli=1; + } else { + kerneli=0; + } mode = (*loopro ? O_RDONLY : O_RDWR); if ((ffd = open(file, mode)) < 0) { @@ -276,8 +351,13 @@ loopinfo64.lo_encrypt_type = atoi(encryption); } else { loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI; - snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE, + if (kerneli) + snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE, + "%s-cbc", encryption); + else + snprintf(loopinfo64.lo_crypt_name, LO_NAME_SIZE, "%s", encryption); + loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0; } } @@ -296,29 +376,98 @@ } #endif + if (keysz==0) + keysz=LO_KEY_SIZE*8; + tried_old=0; +again: switch (loopinfo64.lo_encrypt_type) { case LO_CRYPT_NONE: loopinfo64.lo_encrypt_key_size = 0; break; case LO_CRYPT_XOR: pass = getpass(_("Password: ")); - xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); + xstrncpy(loopinfo64.lo_encrypt_key, pass, keysz/8); loopinfo64.lo_encrypt_key_size = strlen(loopinfo64.lo_encrypt_key); break; - default: + 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: + { +#define HASHLENGTH 20 +#define PASSWDBUFFLEN 130 /* getpass returns only max. 128 bytes, see man getpass */ + char keybits[2*HASHLENGTH]; + char passwdbuff[PASSWDBUFFLEN]; + int keylength; + int i; + pass = xgetpass(pfd, _("Password: ")); - xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); - loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE; + strncpy(passwdbuff+1,pass,PASSWDBUFFLEN-1); + passwdbuff[PASSWDBUFFLEN-1] = '\0'; + passwdbuff[0] = 'A'; + rmd160_hash_buffer(keybits,pass,strlen(pass)); + rmd160_hash_buffer(keybits+HASHLENGTH,passwdbuff,strlen(pass)+1); + memcpy((char*)loopinfo64.lo_encrypt_key,keybits,2*HASHLENGTH); + keylength=0; + for(i=0; crypt_type_tbl[i].id != -1; i++){ + if(loopinfo64.lo_encrypt_type == crypt_type_tbl[i].id){ + keylength = crypt_type_tbl[i].keylength; + break; + } + } + loopinfo64.lo_encrypt_key_size=keylength; + break; + } + default: + if (hash_password) { + char keybits[2*HASHLENGTH]; + char passwdbuff[PASSWDBUFFLEN]; + + pass = xgetpass(pfd, _("Password: ")); + strncpy(passwdbuff+1,pass,PASSWDBUFFLEN-1); + passwdbuff[PASSWDBUFFLEN-1] = '\0'; + passwdbuff[0] = 'A'; + rmd160_hash_buffer(keybits,pass,strlen(pass)); + rmd160_hash_buffer(keybits+HASHLENGTH,passwdbuff,strlen(pass)+1); + memcpy((char*)loopinfo64.lo_encrypt_key,keybits,keysz/8); + } else { + pass = xgetpass(pfd, _("Password: ")); + xstrncpy(loopinfo64.lo_encrypt_key, pass, keysz/8); + } + loopinfo64.lo_encrypt_key_size = keysz/8; } if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { perror("ioctl: LOOP_SET_FD"); return 1; } - close (ffd); - - if (ioctl(fd, LOOP_SET_STATUS64, &loopinfo64) < 0) { + if (kerneli) { + struct loop_info loopinfo; + loop_info64_to_old(&loopinfo64,&loopinfo); + 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 */ + if (tried_old) { + error("The cipher does not exist, or a cipher module " + "needs to be loaded into the kernel"); + perror ("ioctl: LOOP_SET_STATUS"); + goto fail; + } + strncpy (loopinfo64.lo_file_name, file, LO_NAME_SIZE); + loopinfo64.lo_file_name[LO_NAME_SIZE - 1] = 0; + loopinfo64.lo_encrypt_type = name_to_id (encryption); + tried_old = 1; + goto again; + } + } else { + if (ioctl(fd, LOOP_SET_STATUS64, &loopinfo64) < 0) { struct loop_info loopinfo; int errsv = errno; @@ -333,8 +482,10 @@ perror("ioctl: LOOP_SET_STATUS"); goto fail; } + } } + close (ffd); close (fd); if (verbose > 1) printf(_("set_loop(%s,%s,%d): success\n"), @@ -343,6 +494,7 @@ fail: (void) ioctl (fd, LOOP_CLR_FD, 0); + close (ffd); close (fd); return 1; } @@ -411,8 +563,24 @@ 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"), - progname, progname, progname); + %s [ options ] loop_device file # setup\n\ + where options include\n\ + --offset , -o \n\ + start at offset into file.\n\ + --pass-fd , -p \n\ + read passphrase from file descriptor \n\ + instead of the terminal.\n\ + --encryption , -e \n\ + encrypt with .\n\ + Check /proc/crypto or /proc/crypto/cipher for available ciphers.\n\ + --nohashpass, -N\n\ + Don't hash the password given. (previous versions hash, non-debian doesn't.\n\ + --keybits , -k \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"), progname, progname, progname); exit(1); } @@ -445,20 +613,23 @@ int main(int argc, char **argv) { - char *offset, *encryption, *passfd; + char *offset, *encryption, *passfd, *keysize; int delete, off, c; int res = 0; int ro = 0; int pfd = -1; + int keysz = 0; + int hash_password = 1; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); delete = off = 0; - offset = encryption = passfd = NULL; + offset = encryption = passfd = keysize = NULL; progname = argv[0]; - while ((c = getopt(argc,argv,"de:E:o:p:v")) != -1) { + while ((c = getopt_long(argc,argv,"de:E:hk:No:p:v", + longopts, NULL)) != EOF) { switch (c) { case 'd': delete = 1; @@ -467,6 +638,12 @@ case 'e': encryption = optarg; break; + case 'N': + hash_password=0; + break; + case 'k': + keysize = optarg; + break; case 'o': offset = optarg; break; @@ -494,8 +671,10 @@ usage(); if (passfd && sscanf(passfd,"%d",&pfd) != 1) usage(); + if (keysize && sscanf(keysize,"%d",&keysz) != 1) + usage(); res = set_loop(argv[optind], argv[optind+1], off, - encryption, pfd, &ro); + encryption, pfd, keysz, &ro, hash_password); } return res; } --- util-linux-2.12.orig/mount/lomount.h +++ util-linux-2.12/mount/lomount.h @@ -1,6 +1,6 @@ extern int verbose; extern int set_loop(const char *, const char *, int, const char *, - int, int *); + int, int, int *, int); extern int del_loop(const char *); extern int is_loop_device(const char *); extern char * find_unused_loop_device(void); --- util-linux-2.12.orig/mount/loop.h +++ util-linux-2.12/mount/loop.h @@ -1,8 +1,39 @@ -#define LO_CRYPT_NONE 0 -#define LO_CRYPT_XOR 1 -#define LO_CRYPT_DES 2 +#define LO_CRYPT_NONE 0 +#define LO_CRYPT_XOR 1 +#define LO_CRYPT_DES 2 #define LO_CRYPT_CRYPTOAPI 18 +#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 + #define LOOP_SET_FD 0x4C00 #define LOOP_CLR_FD 0x4C01 #define LOOP_SET_STATUS 0x4C02 --- util-linux-2.12.orig/mount/losetup.8 +++ util-linux-2.12/mount/losetup.8 @@ -50,19 +50,24 @@ .B \-e option.) .SH OPTIONS -.IP \fB\-d\fP -Detach the file or device associated with the specified loop device. +.IP "\fB\-\-delete, \-\-detach, \-d\fP" +detach the file or device associated with the specified loop device. .IP "\fB\-E \fIencryption_type\fP" Enable data encryption with specified number. -.IP "\fB\-e \fIencryption_name\fP" +.IP "\fB\-\-encryption, \-e \fIencryption\fP" Enable data encryption with specified name. -.IP "\fB\-o \fIoffset\fP" +.IP "\fB\-\-nohashpass, \-N\fP" +Do not hash the password. Many previous Debian releases run the password through a +hash function, non-Debian systems appear to. +.IP "\fB\-\-offset, \-o \fIoffset\fP" The data start is moved \fIoffset\fP bytes into the specified file or device. -.IP "\fB\-p \fInum\fP" +.IP "\fB\-\-pass-fd, \-p \fInum\fP" Read the passphrase from file descriptor with number .I num instead of from the terminal. +.IP "\fB\-\-keybits, \-k \fInum\fP" +set the number of bits to use in key to \fInum\fP. .SH RETURN VALUE .B losetup returns 0 on success, nonzero on failure. When @@ -109,6 +114,9 @@ .fi .SH RESTRICTION DES encryption is painfully slow. On the other hand, XOR is terribly weak. +Both are insecure nowadays. Some ciphers may require a licence for you to be +allowed to use them. +.fi .\" .SH AUTHORS .\" .nf .\" Original version: Theodore Ts'o --- util-linux-2.12.orig/mount/mount.8 +++ util-linux-2.12/mount/mount.8 @@ -270,6 +270,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 . @@ -633,6 +639,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 @@ -1696,7 +1711,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. @@ -1767,7 +1785,7 @@ .BR e2label (8), .BR xfs_admin (8), .BR mountd (8), -.BR nfsd (8), +.BR rpc.nfsd (8), .BR mke2fs (8), .BR tune2fs (8), .BR losetup (8) --- util-linux-2.12.orig/mount/mount.c +++ util-linux-2.12/mount/mount.c @@ -92,6 +92,9 @@ /* Nonzero for chatty (-v). */ int verbose = 0; +/* Do we hash the password or not */ +int hash_password = 1; + /* Nonzero for sloppy (-s). */ int sloppy = 0; @@ -116,6 +119,9 @@ /* Contains the fd to read the passphrase from, if any. */ static int pfd = -1; +/* Contains the preferred keysize in bits we want to use */ +static int keysz = 0; + /* Map from -o and fstab option strings to the flag argument to mount(2). */ struct opt_map { const char *opt; /* option name */ @@ -195,7 +201,7 @@ }; static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption, - *opt_speed; + *opt_keybits, *opt_nohashpass, *opt_speed; static struct string_opt_map { char *tag; @@ -206,6 +212,8 @@ { "vfs=", 1, &opt_vfstype }, { "offset=", 0, &opt_offset }, { "encryption=", 0, &opt_encryption }, + { "keybits=", 0, &opt_keybits }, + { "nohashpass", 0, &opt_nohashpass }, { "speed=", 0, &opt_speed }, { NULL, 0, NULL } }; @@ -586,7 +594,8 @@ *type = opt_vfstype; } - *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption); + *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption || + opt_keybits); *loopfile = *spec; if (*loop) { @@ -604,8 +613,12 @@ 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, pfd, &loopro)) { + if (!keysz && opt_keybits) + keysz = strtoul(opt_keybits, NULL, 0); + if (opt_nohashpass) + hash_password=0; + if (set_loop (*loopdev, *loopfile, offset, opt_encryption, pfd, + keysz, &loopro, hash_password)) { if (verbose) printf(_("mount: failed setting up loop device\n")); return EX_FAIL; @@ -1371,6 +1384,7 @@ { "options", 1, 0, 'o' }, { "test-opts", 1, 0, 'O' }, { "pass-fd", 1, 0, 'p' }, + { "keybits", 1, 0, 'k' }, { "types", 1, 0, 't' }, { "bind", 0, 0, 128 }, { "replace", 0, 0, 129 }, @@ -1424,6 +1438,8 @@ int c, result = 0, specseen; char *options = NULL, *test_opts = NULL, *spec, *node; char *volumelabel = NULL; + char *passfd = NULL; + char *keysize = NULL; char *uuid = NULL; char *types = NULL; struct mntentchn *mc; @@ -1447,7 +1463,7 @@ initproctitle(argc, argv); #endif - while ((c = getopt_long (argc, argv, "afFhilL:no:O:p:rsU:vVwt:", + while ((c = getopt_long (argc, argv, "afFhilL:k:no:O:p:rsU:vVwt:", longopts, NULL)) != -1) { switch (c) { case 'a': /* mount everything in fstab */ @@ -1471,6 +1487,9 @@ case 'L': volumelabel = optarg; break; + case 'k': + keysize = optarg; + break; case 'n': /* do not write /etc/mtab */ ++nomtab; break; @@ -1598,6 +1617,11 @@ } 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")); + if (keysize && sscanf(keysize,"%d",&keysz) != 1) + die (EX_USAGE, _("mount: argument to --keybits or -k must be a number")); + switch (argc+specseen) { case 0: /* mount -a */ --- util-linux-2.12.orig/mount/rmd160.c +++ util-linux-2.12/mount/rmd160.c @@ -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 . 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 /* (mm) for memcpy */ +#include /* (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 ); +} --- util-linux-2.12.orig/mount/rmd160.h +++ util-linux-2.12/mount/rmd160.h @@ -0,0 +1,9 @@ +#ifndef RMD160_H +#define RMD160_H + +void +rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length ); + +#endif /*RMD160_H*/ + +