ripemd160/hashalot-0.2.0 gives a different hash than ripemd160/hashalot-0.3 for the same hashed string. Reproducible: Always Steps to Reproduce: 1.Emerge app-crypt/hashalot/hashalot-0.2.0 2./usr/sbin/rmd160 [ type a string to hash, and enter] 3.Note result 4.Emerge app-crypt/hashalot/hashalot-0.3.0 5./usr/sbin/rmd160 [ type same string as above, and enter] 6. Note result Actual Results: Results in step 3 and 6 above are different. My tests with the string 'gentoo' (without single quotes) string 'gentoo' on hashalot 0.2.0 rmd160
ripemd160/hashalot-0.2.0 gives a different hash than ripemd160/hashalot-0.3 for the same hashed string. Reproducible: Always Steps to Reproduce: 1.Emerge app-crypt/hashalot/hashalot-0.2.0 2./usr/sbin/rmd160 [ type a string to hash, and enter] 3.Note result 4.Emerge app-crypt/hashalot/hashalot-0.3.0 5./usr/sbin/rmd160 [ type same string as above, and enter] 6. Note result Actual Results: Results in step 3 and 6 above are different. My tests with the string 'gentoo' (without single quotes) string 'gentoo' on hashalot 0.2.0 rmd160 í-rÍWs_}®Åx·°I@5?þ&Û&¦ÆçÝ string 'gentoo' on hashalot 0.3.0 rmd160 í-rÍWs_}®Åx·°Is Expected Results: Results in step 3 and 6 should be the same because this will break cryptoapi. Loopback filesystems created with the aid of rmd160/hashalot-0.2.0 as password hashing tool will no longer mount if hashalot is upgraded. Portage 2.0.50-r8 (default-x86-1.4, gcc-3.3.3, glibc-2.3.3.20040420-r0, 2.6.7-hardened-r2) ================================================================= System uname: 2.6.7-hardened-r2 i686 Intel(R) Pentium(R) 4 CPU 2.66GHz Gentoo Base System version 1.5.1 distcc 2.14 i686-pc-linux-gnu (protocols 1 and 2) (default port 3632) [enabled] Autoconf: sys-devel/autoconf-2.59-r4 Automake: sys-devel/automake-1.8.5-r1 ACCEPT_KEYWORDS="x86 ~x86" AUTOCLEAN="yes" CFLAGS="-O2 -march=pentium4 -pipe -fomit-frame-pointer -mmmx -msse -msse2" CHOST="i686-pc-linux-gnu" COMPILER="gcc3" CONFIG_PROTECT="/etc /etc/apache2 /etc/bootsplash /etc/conf.d /etc/modules/autoload.d /etc/shorewall /etc/ssh /usr/X11R6/lib/X11/xkb /usr/kde/2/share/config /usr/kde/3.2/share/config /usr/kde/3.3/share/config /usr/kde/3/share/config /usr/lib/mozilla/defaults/pref /usr/share/config /var/qmail/control" CONFIG_PROTECT_MASK="/etc/gconf /etc/sound /etc/terminfo /usr/X11R6/ /usr/kde/ /etc/env.d" CXXFLAGS="-O2 -march=pentium4 -pipe -fomit-frame-pointer -mmmx -msse -msse2" DISTDIR="/usr/portage/distfiles" FEATURES="autoaddcvs ccache distcc sandbox" GENTOO_MIRRORS="ftp://ftp.snt.utwente.nl/pub/os/linux/gentoo" MAKEOPTS="-j4" PKGDIR="/usr/portage/packages" PORTAGE_TMPDIR="/disk/portage/build" PORTDIR="/usr/portage" PORTDIR_OVERLAY="/usr/local/portage" SYNC="rsync://rsync.gentoo.org/gentoo-portage" USE="X alsa apm arts avi berkdb bonobo cdr crypt cups dvd encode esd ethereal flash foomaticdb gd gdbm gif gl gnome gpm gtk gtk2 gtkhtml imlib java jpeg kde libg++ libwww mad mikmod mmx motif mozilla moznocompose moznoirc moznomail mpeg mysql ncurses nls oggvorbis opengl oss pam pdflib perl png python qt quicktime readline sdl slang spell sse ssl svga tcltk tcpd tiff truetype unicode x86 xml xml2 xmms xv zlib"
Increased severity per request.
http://defiant.noxa.de/~pappy/hashalot-2-3.diff --- ../../../hashalot-0.2.0/work/hashalot-0.2.0/hashalot.c 2003-12-10 03:30:10.000000000 +0100 +++ ./hashalot.c 2004-04-29 06:06:23.000000000 +0200 @@ -6,9 +6,9 @@ ** an encryption key. ** ** USAGE: -** hashalot [ -s _salt_ ] _hashtype_ +** hashalot [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] _hashtype_ ** OR -** _hashtype_ [ -s _salt_ ] +** _hashtype_ [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] ** ** Most of the code was cribbed from the kerneli.org patch to util-linux, ** by Marc Mutz <Marc@Mutz.com>. Most of what wasn't, was cribbed from GnuPG, @@ -28,13 +28,12 @@ #include "rmd160.h" #include "sha512.h" -#define HASHBUFFLEN 32 #define PASSWDBUFFLEN 130 -typedef int (*phash_func_t)(char dest[HASHBUFFLEN], const char src[], size_t src_len); +typedef int (*phash_func_t)(char dest[], size_t dest_len, const char src[], size_t src_len); static int -phash_rmd160(char dest[HASHBUFFLEN], const char src[], size_t src_len) +phash_rmd160(char dest[], size_t dest_len, const char src[], size_t src_len) { char tmp[PASSWDBUFFLEN] = { 'A', 0, }; char key[RMD160_HASH_SIZE * 2] = { 0, }; @@ -45,56 +44,50 @@ rmd160_hash_buffer(key, src, src_len); rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp, src_len + 1 /* dangerous! */); - memcpy(dest, key, HASHBUFFLEN); + memcpy(dest, key, dest_len); memset (tmp, 0, PASSWDBUFFLEN); /* paranoia */ memset (key, 0, RMD160_HASH_SIZE * 2); /* paranoia */ - return HASHBUFFLEN; + return dest_len; } static int -phash_rmd160compat(char dest[HASHBUFFLEN], const char src[], size_t src_len) +phash_sha256(char dest[], size_t dest_len, const char src[], size_t src_len) { - phash_rmd160(dest,src,src_len); - return 16; + memset(dest, 0, dest_len); + sha256_hash_buffer((char *) src, src_len, dest, dest_len); + return dest_len; } static int -phash_sha256(char dest[HASHBUFFLEN], const char src[], size_t src_len) +phash_sha384(char dest[], size_t dest_len, const char src[], size_t src_len) { - memset(dest, 0, HASHBUFFLEN); - sha256_hash_buffer((char *) src, src_len, dest, HASHBUFFLEN); - return HASHBUFFLEN; + memset(dest, 0, dest_len); + sha384_hash_buffer((char *) src, src_len, dest, dest_len); + return dest_len; } static int -phash_sha384(char dest[HASHBUFFLEN], const char src[], size_t src_len) +phash_sha512(char dest[], size_t dest_len, const char src[], size_t src_len) { - memset(dest, 0, HASHBUFFLEN); - sha384_hash_buffer((char *) src, src_len, dest, HASHBUFFLEN); - return HASHBUFFLEN; -} - -static int -phash_sha512(char dest[HASHBUFFLEN], const char src[], size_t src_len) -{ - memset(dest, 0, HASHBUFFLEN); - sha512_hash_buffer((char *) src, src_len, dest, HASHBUFFLEN); - return HASHBUFFLEN; + memset(dest, 0, dest_len); + sha512_hash_buffer((char *) src, src_len, dest, dest_len); + return dest_len; } struct func_table_t { const char *name; phash_func_t func; + size_t def_length; } static func_table[] = { - { "ripemd160", phash_rmd160 }, - { "rmd160", phash_rmd160 }, - { "rmd160compat", phash_rmd160compat }, - { "sha256", phash_sha256 }, - { "sha384", phash_sha384 }, - { "sha512", phash_sha512 }, - { 0, 0 } + { "ripemd160", phash_rmd160, 20 }, + { "rmd160", phash_rmd160, 20 }, + { "rmd160compat", phash_rmd160, 16 }, + { "sha256", phash_sha256, 32 }, + { "sha384", phash_sha384, 48 }, + { "sha512", phash_sha512, 64 }, + { 0, 0, 0 } }; static int @@ -103,14 +96,12 @@ struct func_table_t *p = func_table; fprintf (stderr, - "%s: missing or unknown hash type requested\n" - "\n" "usage:\n" - " hashalot [ -s SALT ] HASHTYPE\n" + " hashalot [ -x ] [ -s SALT ] [ -n _#bytes_ ] HASHTYPE\n" " or\n" - " HASHTYPE [ -s SALT ]\n" + " HASHTYPE [ -x ] [ -s SALT ] [ -n _#bytes_ ]\n" "\n" - "supported values for HASHTYPE: ", argv0); + "supported values for HASHTYPE: "); for (; p->name; ++p) fprintf (stderr, "%s ", p->name); @@ -121,7 +112,7 @@ } static phash_func_t -phash_lookup(const char phash_name[]) +phash_lookup(const char phash_name[], size_t *length) { struct func_table_t *p = func_table; @@ -130,6 +121,7 @@ for (; p->name && strcmp(phash_name, p->name); ++p); + if (length) *length = p->def_length; return p->func; } @@ -190,40 +182,80 @@ /* function to append a "salt" to the passphrase, to better resist * dictionary attacks */ static char * -salt_passphrase(const char *pass, const char *salt) { +salt_passphrase(char *pass, char *salt) { char *buf = xmalloc(strlen(pass) + strlen(salt) + 1); sprintf(buf, "%s%s", pass, salt); + + memset (pass, 0, strlen (pass)); /* paranoia */ free(pass); + return buf; } +static void +hexify(char *hash, size_t hashlen) { + int i; + char *h = xmalloc(hashlen); + memcpy(h, hash, hashlen); + + for (i=0; i < hashlen; i++) + snprintf((hash + 2*i), 3, "%.2x", (unsigned char) h[i]); + strcat(hash, "\n"); + + memset(h, 0, hashlen); /* paranoia */ + free(h); +} + int main(int argc, char *argv[]) { - char *pass, passhash[HASHBUFFLEN], *salt = NULL; + char *pass, *passhash, *salt = NULL, *p; + size_t hashlen = 0; phash_func_t func; - int hashlen, c; + int hex_output = 0, c; - while ((c = getopt(argc, argv, "s:")) != -1) { + while ((c = getopt(argc, argv, "n:s:x")) != -1) { switch (c) { + case 'n': + hashlen = strtoul(optarg, &p, 0); + if (*p != '\0' || *optarg == '\0') { + fprintf (stderr, + "%s: argument to -n option must be numeric\n", + argv[0]); + show_usage(argv[0]); + exit(EXIT_FAILURE); + } + break; case 's': salt = optarg; break; + case 'x': + hex_output++; + break; default: show_usage(argv[0]); + exit(EXIT_FAILURE); } } - if (!(func = phash_lookup(basename(argv[0])))) + if (!(func = phash_lookup(basename(argv[0]), (hashlen ? NULL : &hashlen)))) /* lookup failed, so try next argv */ - if (!(func = phash_lookup(argv[optind]))) { + if (!(func = phash_lookup(argv[optind], (hashlen ? NULL : &hashlen)))) { /* lookup failed again */ - show_usage (*argv); + fprintf (stderr, + "%s: missing or unknown hash type requested\n", + argv[0]); + show_usage(argv[0]); exit(EXIT_FAILURE); } assert (func != 0); + /* allocate memory for the password hash: + * enough for 2 hex digits per byte of the requested hash length, + * plus a newline, plus a null */ + passhash = xmalloc(2*hashlen + 2); + /* try to lock memory so it doesn't get swapped out for sure */ if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { perror("mlockall"); @@ -234,13 +266,20 @@ pass = xgetpass("Enter passphrase: "); if (salt) pass = salt_passphrase(pass, salt); - hashlen = func(passhash, pass, strlen(pass)); + hashlen = func(passhash, hashlen, pass, strlen(pass)); memset (pass, 0, strlen (pass)); /* paranoia */ + free(pass); + + if (hex_output) { + hexify(passhash, hashlen); + hashlen = hashlen * 2 + 1; + } if (write(STDOUT_FILENO, passhash, hashlen) != hashlen) perror("write"); - memset (passhash, 0, HASHBUFFLEN); /* paranoia again */ + memset (passhash, 0, hashlen); /* paranoia again */ + free(passhash); exit(EXIT_SUCCESS); }
can you please try the option [ -n _#bytes_ ] and see if you can replay the old behaviour of 2.0 with certain values? the diff shows that it added that option and also changed the default size as you noticed to me on irc. as in the example, HASHBUFFLEN was superceded by a given value dest_len. and 2.0 defines it this way: ./work/hashalot-0.2.0/hashalot.c:#define HASHBUFFLEN 32 please test it and help me to resolve it further, Alex
Cannot fix idle bugs without help of user that opened it. -Alex