Subject: lib/12045: skey/libskey SHA bug
To: None <gnats-bugs@gnats.netbsd.org>
From: None <valdes@uchicago.edu>
List: netbsd-bugs
Date: 01/25/2001 21:09:20
>Number:         12045
>Category:       lib
>Synopsis:       skey generates incorrect passwords when using SHA-1
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jan 25 21:12:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     John Valdes
>Release:        NetBSD-1.5
>Organization:
	University of Chicago
>Environment:
	Mac PowerBook G3, NetBSD-1.5, macppc, libskey.so.1 & libc.so.12
System: NetBSD scallop 1.5 NetBSD 1.5 (SCALLOP) #1: Sun Jan 21 18:25:09 CST 2001 root@scallop:/usr/src/sys/arch/macppc/compile/SCALLOP macppc


>Description:
	One-time passwords generated with /usr/bin/skey when using sha1
	as the hash function are incorrect.  They do not match the test
	cases given in Appendix C of RFC2289.
>How-To-Repeat:
	The following illustrates the problem:

		prompt> skey -x -t sha1 0 TeSt
		Enter secret password: This is a test.
		E16A 9EBB F48F 9D97

	The correct response should be "BB9E 6AE1 979D 8FF4".  From this
	example, that the 2 four-byte ints making up this response are
	byte-swapped.

	Note that the PowerPC is big-endian; I believe the same problem
	exists on little-endian systems.  I haven't tested this directly
	(I don't have NetBSD installed on any little-endian systems), but
	on an i386 system running OpenBSD 2.6, which has almost identical
	source for the skey routines, I get the same, incorrect results
	with skey when using sha1.  However, please test this on NetBSD-1.5
	running on an i386 or other little-endian system.

>Fix:
	The fix is to swap the bytes returned by the SHA1 hash functions
	before returning results to skey.  This can be fixed in
	/usr/src/lib/libskey/skeysubr.c.  Here's a patch.  Note that if
	this bug isn't present in little-endian systems, then in the patch
	below, replace the calls to "bswap32()" with "htole32()":

*** skeysubr.c.dist	Mon Jul 17 14:55:53 2000
--- skeysubr.c	Thu Jan 25 16:40:48 2001
***************
*** 160,166 ****
  	SHA1_CTX sha;
  	u_int32_t results[5];
  	size_t buflen;
- 	int i, j;
  
  	if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
  		return -1;
--- 160,165 ----
***************
*** 177,195 ****
  	results[0] ^= results[4];
  
  	/*
! 	 * Even though my readings of rfc2289 indicate that this is
! 	 * wrong (it converts stuff to big endian), it is needed to
! 	 * make the output match up the regression tests in said rfc.
! 	 * Something is wrong here? --mjl
  	 */
! 		
! 	for(i=j=0; j<8; i++, j+=4)
! 		{
! 		result[j+3] = (unsigned char)(results[i] & 0xff);
! 		result[j+2] = (unsigned char)((results[i] >> 8) & 0xff);
! 		result[j+1] = (unsigned char)((results[i] >> 16) & 0xff);
! 		result[j+0] = (unsigned char)((results[i] >> 24) & 0xff);
! 		}
  
  	return(0);
  }
--- 176,188 ----
  	results[0] ^= results[4];
  
  	/*
! 	 * RFC2289 indicates SHA1 results should be stored in little-endian
! 	 * order; we seem to need to swap byte regardless of host byte order
! 	 * (else we would use htole32()). -jpv
  	 */
! 	results[0] = bswap32(results[0]);
! 	results[1] = bswap32(results[1]);
! 	(void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
  
  	return(0);
  }
***************
*** 266,272 ****
  {
  	SHA1_CTX sha;
  	u_int32_t results[5];
- 	int i, j;
  	
  	SHA1Init(&sha);
  	SHA1Update(&sha, (unsigned char *)x, SKEY_BINKEY_SIZE);
--- 259,264 ----
***************
*** 277,289 ****
  	results[1] ^= results[3];
  	results[0] ^= results[4];
  
! 	for(i=j=0; j<8; i++, j+=4)
! 		{
! 		x[j+3] = (unsigned char)(results[i] & 0xff);
! 		x[j+2] = (unsigned char)((results[i] >> 8) & 0xff);
! 		x[j+1] = (unsigned char)((results[i] >> 16) & 0xff);
! 		x[j+0] = (unsigned char)((results[i] >> 24) & 0xff);
! 		}
  }
  
  #if 0
--- 269,278 ----
  	results[1] ^= results[3];
  	results[0] ^= results[4];
  
! 	/* Swap bytes */
! 	results[0] = bswap32(results[0]);
! 	results[1] = bswap32(results[1]);
! 	(void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE);
  }
  
  #if 0
>Release-Note:
>Audit-Trail:
>Unformatted: