Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 56421 - ripemd160 hashing inconsistencies across different versions of hashalot
Summary: ripemd160 hashing inconsistencies across different versions of hashalot
Status: RESOLVED INVALID
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: [OLD] Unspecified (show other bugs)
Hardware: x86 Linux
: High blocker (vote)
Assignee: Alexander Gabert (RETIRED)
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-07-08 01:04 UTC by Simpleguy
Modified: 2004-09-23 18:33 UTC (History)
3 users (show)

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Simpleguy 2004-07-08 01:04:57 UTC
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 
Comment 1 Simpleguy 2004-07-08 01:04:57 UTC
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"
Comment 2 Chris White (RETIRED) gentoo-dev 2004-07-08 02:12:54 UTC
Increased severity per request.
Comment 3 Alexander Gabert (RETIRED) gentoo-dev 2004-07-08 04:15:13 UTC
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);
 }

Comment 4 Alexander Gabert (RETIRED) gentoo-dev 2004-07-08 04:21:57 UTC
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
Comment 5 Alexander Gabert (RETIRED) gentoo-dev 2004-09-23 18:33:11 UTC
Cannot fix idle bugs without help of user that opened it.

-Alex