From: Tom Yu Date: Tue, 28 Oct 1997 21:39:36 +0000 (+0000) Subject: * shs.c, sha_glue.c, hmac_sha.c: Fix to deal with LONG wider than X-Git-Tag: krb5-1.1-beta1~967 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=052d558202badc4e9e81641058c89d17f656e2f5;p=krb5.git * shs.c, sha_glue.c, hmac_sha.c: Fix to deal with LONG wider than 32 bits. * t_shs.c: Print out the actual and expected values on error. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10258 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/crypto/sha/ChangeLog b/src/lib/crypto/sha/ChangeLog index 03521a5b7..154f7b679 100644 --- a/src/lib/crypto/sha/ChangeLog +++ b/src/lib/crypto/sha/ChangeLog @@ -1,3 +1,10 @@ +Tue Oct 28 16:37:18 1997 Tom Yu + + * shs.c, sha_glue.c, hmac_sha.c: Fix to deal with LONG wider than + 32 bits. + + * t_shs.c: Print out the actual and expected values on error. + Sat Feb 22 18:52:09 1997 Richard Basch * Makefile.in: Use some of the new library list build rules in diff --git a/src/lib/crypto/sha/hmac_sha.c b/src/lib/crypto/sha/hmac_sha.c index 01b00899e..d57092e69 100644 --- a/src/lib/crypto/sha/hmac_sha.c +++ b/src/lib/crypto/sha/hmac_sha.c @@ -16,19 +16,28 @@ hmac_sha(text, text_len, key, key_len, digest) krb5_octet k_ipad[PAD_SZ]; /* inner padding - key XORd with ipad */ krb5_octet k_opad[PAD_SZ]; /* outer padding - key XORd with opad */ int i; + krb5_octet *cp; + LONG *lp; /* sanity check parameters */ if (!text || !key || !digest) /* most heinous, probably should log something */ return EINVAL; - /* if key is longer than 64 bytes reset it to key=MD5(key) */ + /* if key is longer than 64 bytes reset it to key=SHA(key) */ if (key_len > sizeof(k_ipad)) { shsInit(&context); shsUpdate(&context, key, key_len); shsFinal(&context); - memcpy(digest, context.digest, SHS_DIGESTSIZE); + cp = digest; + lp = context.digest; + while (cp < digest + SHS_DIGESTSIZE) { + *cp++ = (*lp >> 24) & 0xff; + *cp++ = (*lp >> 16) & 0xff; + *cp++ = (*lp >> 8) & 0xff; + *cp++ = *lp++ & 0xff; + } key = digest; key_len = SHS_DIGESTSIZE; } @@ -62,7 +71,14 @@ hmac_sha(text, text_len, key, key_len, digest) shsUpdate(&context, text, text_len); shsFinal(&context); - memcpy(digest, context.digest, SHS_DIGESTSIZE); + cp = digest; + lp = context.digest; + while (cp < digest + SHS_DIGESTSIZE) { + *cp++ = (*lp >> 24) & 0xff; + *cp++ = (*lp >> 16) & 0xff; + *cp++ = (*lp >> 8) & 0xff; + *cp++ = *lp++ & 0xff; + } /* * perform outer SHA @@ -72,7 +88,14 @@ hmac_sha(text, text_len, key, key_len, digest) shsUpdate(&context, digest, SHS_DIGESTSIZE); shsFinal(&context); - memcpy(digest, context.digest, SHS_DIGESTSIZE); + cp = digest; + lp = context.digest; + while (cp < digest + SHS_DIGESTSIZE) { + *cp++ = (*lp >> 24) & 0xff; + *cp++ = (*lp >> 16) & 0xff; + *cp++ = (*lp >> 8) & 0xff; + *cp++ = *lp++ & 0xff; + } return 0; } diff --git a/src/lib/crypto/sha/sha_glue.c b/src/lib/crypto/sha/sha_glue.c index 3a57e0182..58a93b723 100644 --- a/src/lib/crypto/sha/sha_glue.c +++ b/src/lib/crypto/sha/sha_glue.c @@ -25,6 +25,8 @@ krb5_sha_sum_func(in, in_length, seed, seed_length, outcksum) krb5_checksum FAR *outcksum; { krb5_octet *input = (krb5_octet *)in; + krb5_octet *cp; + LONG *lp; SHS_INFO working; if (outcksum->length < SHS_DIGESTSIZE) @@ -37,9 +39,14 @@ krb5_sha_sum_func(in, in_length, seed, seed_length, outcksum) outcksum->checksum_type = CKSUMTYPE_NIST_SHA; outcksum->length = SHS_DIGESTSIZE; - memcpy((char *)outcksum->contents, - (char *)&working.digest[0], - outcksum->length); + cp = outcksum->contents; + lp = working.digest; + while (lp < working.digest + 16) { + *cp++ = (*lp >> 24) & 0xff; + *cp++ = (*lp >> 16) & 0xff; + *cp++ = (*lp >> 8) & 0xff; + *cp++ = (*lp++) & 0xff; + } memset((char *)&working, 0, sizeof(working)); return 0; } @@ -55,6 +62,8 @@ krb5_sha_verify_func(cksum, in, in_length, seed, seed_length) krb5_octet *input = (krb5_octet *)in; SHS_INFO working; krb5_error_code retval; + int i; + krb5_octet *cp; if (cksum->checksum_type != CKSUMTYPE_NIST_SHA) return KRB5KRB_AP_ERR_INAPP_CKSUM; @@ -66,10 +75,14 @@ krb5_sha_verify_func(cksum, in, in_length, seed, seed_length) shsFinal(&working); retval = 0; - if (memcmp((char *) cksum->contents, - (char *) &working.digest[0], - cksum->length)) - retval = KRB5KRB_AP_ERR_BAD_INTEGRITY; + for (i = 0, cp = cksum->contents; i < 5; i++, cp += 4) { + if (working.digest[i] != + (LONG) cp[0] << 24 | (LONG) cp[1] << 16 | + (LONG) cp[2] << 8 | (LONG) cp[3]) { + retval = KRB5KRB_AP_ERR_BAD_INTEGRITY; + break; + } + } memset((char *) &working, 0, sizeof(working)); return retval; } diff --git a/src/lib/crypto/sha/shs.c b/src/lib/crypto/sha/shs.c index ee4965036..e18f3af9e 100644 --- a/src/lib/crypto/sha/shs.c +++ b/src/lib/crypto/sha/shs.c @@ -33,7 +33,7 @@ /* 32-bit rotate left - kludged with shifts */ -#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) ) +#define ROTL(n,X) (((X) << (n)) & 0xffffffff | ((X) >> (32 - n))) /* The initial expanding function. The hash function is defined over an 80-word expanded input array W, where the first 16 are copies of the input @@ -71,7 +71,8 @@ the next 20 values from the W[] array each time */ #define subRound(a, b, c, d, e, f, k, data) \ - ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) ) + ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, \ + e &= 0xffffffff, b = ROTL( 30, b ) ) /* Initialize the SHS values */ @@ -112,7 +113,7 @@ void SHSTransform(digest, data) C = digest[ 2 ]; D = digest[ 3 ]; E = digest[ 4 ]; - memcpy( eData, data, SHS_DATASIZE ); + memcpy(eData, data, sizeof (eData)); /* Heavy mangling, in 4 sub-rounds of 20 interations each. */ subRound( A, B, C, D, E, f1, K1, eData[ 0 ] ); @@ -201,10 +202,15 @@ void SHSTransform(digest, data) /* Build message digest */ digest[ 0 ] += A; + digest[ 0 ] &= 0xffffffff; digest[ 1 ] += B; + digest[ 1 ] &= 0xffffffff; digest[ 2 ] += C; + digest[ 2 ] &= 0xffffffff; digest[ 3 ] += D; + digest[ 3 ] &= 0xffffffff; digest[ 4 ] += E; + digest[ 4 ] &= 0xffffffff; } /* When run on a little-endian CPU we need to perform byte reversal on an @@ -250,47 +256,93 @@ void shsUpdate(shsInfo, buffer, count) int count; { LONG tmp; - int dataCount; + int dataCount, canfill; + LONG *lp; /* Update bitcount */ tmp = shsInfo->countLo; - if ( ( shsInfo->countLo = tmp + ( ( LONG ) count << 3 ) ) < tmp ) - shsInfo->countHi++; /* Carry from low to high */ + shsInfo->countLo = tmp + (((LONG) count) << 3 ); + if ((shsInfo->countLo &= 0xffffffff) < tmp) + shsInfo->countHi++; /* Carry from low to high */ shsInfo->countHi += count >> 29; /* Get count of bytes already in data */ - dataCount = ( int ) ( tmp >> 3 ) & 0x3F; + dataCount = (int) (tmp >> 3) & 0x3F; /* Handle any leading odd-sized chunks */ - if( dataCount ) - { - BYTE *p = ( BYTE * ) shsInfo->data + dataCount; - - dataCount = SHS_DATASIZE - dataCount; - if( count < dataCount ) - { - memcpy( p, buffer, count ); - return; - } - memcpy( p, buffer, dataCount ); - longReverse( shsInfo->data, SHS_DATASIZE ); - SHSTransform( shsInfo->digest, shsInfo->data ); - buffer += dataCount; - count -= dataCount; - } + if (dataCount) { + lp = shsInfo->data + dataCount / 4; + canfill = (count >= dataCount); + dataCount = SHS_DATASIZE - dataCount; + + if (dataCount % 4) { + /* Fill out a full 32 bit word first if needed -- this + is not very efficient (computed shift amount), + but it shouldn't happen often. */ + while (dataCount % 4 && count > 0) { + *lp |= (LONG) *buffer++ << ((3 - dataCount++ % 4) * 8); + count--; + } + lp++; + } + while (lp < shsInfo->data + 16) { + *lp = (LONG) *buffer++ << 24; + *lp |= (LONG) *buffer++ << 16; + *lp |= (LONG) *buffer++ << 8; + *lp++ |= (LONG) *buffer++; + if ((count -= 4) < 4 && lp < shsInfo->data + 16) { + *lp = 0; + switch (count % 4) { + case 3: + *lp |= (LONG) buffer[2] << 8; + case 2: + *lp |= (LONG) buffer[1] << 16; + case 1: + *lp |= (LONG) buffer[0] << 24; + } + break; + count = 0; + } + } + if (canfill) { + SHSTransform(shsInfo->digest, shsInfo->data); + } + } /* Process data in SHS_DATASIZE chunks */ - while( count >= SHS_DATASIZE ) - { - memcpy( shsInfo->data, buffer, SHS_DATASIZE ); - longReverse( shsInfo->data, SHS_DATASIZE ); - SHSTransform( shsInfo->digest, shsInfo->data ); - buffer += SHS_DATASIZE; - count -= SHS_DATASIZE; - } - - /* Handle any remaining bytes of data. */ - memcpy( shsInfo->data, buffer, count ); + while (count >= SHS_DATASIZE) { + lp = shsInfo->data; + while (lp < shsInfo->data + 16) { + *lp = ((LONG) *buffer++) << 24; + *lp |= ((LONG) *buffer++) << 16; + *lp |= ((LONG) *buffer++) << 8; + *lp++ |= (LONG) *buffer++; + } + SHSTransform(shsInfo->digest, shsInfo->data); + count -= SHS_DATASIZE; + } + + if (count > 0) { + lp = shsInfo->data; + while (count > 4) { + *lp = ((LONG) *buffer++) << 24; + *lp |= ((LONG) *buffer++) << 16; + *lp |= ((LONG) *buffer++) << 8; + *lp++ |= (LONG) *buffer++; + count -= 4; + } + *lp = 0; + switch (count % 4) { + case 0: + *lp |= ((LONG) buffer[3]); + case 3: + *lp |= ((LONG) buffer[2]) << 8; + case 2: + *lp |= ((LONG) buffer[1]) << 16; + case 1: + *lp |= ((LONG) buffer[0]) << 24; + } + } } /* Final wrapup - pad to SHS_DATASIZE-byte boundary with the bit pattern @@ -300,39 +352,41 @@ void shsFinal(shsInfo) SHS_INFO *shsInfo; { int count; + LONG *lp; BYTE *dataPtr; /* Compute number of bytes mod 64 */ - count = ( int ) shsInfo->countLo; - count = ( count >> 3 ) & 0x3F; + count = (int) shsInfo->countLo; + count = (count >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ - dataPtr = ( BYTE * ) shsInfo->data + count; - *dataPtr++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = SHS_DATASIZE - 1 - count; - - /* Pad out to 56 mod 64 */ - if( count < 8 ) - { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset( dataPtr, 0, count ); - longReverse( shsInfo->data, SHS_DATASIZE ); - SHSTransform( shsInfo->digest, shsInfo->data ); - - /* Now fill the next block with 56 bytes */ - memset( shsInfo->data, 0, SHS_DATASIZE - 8 ); - } - else - /* Pad block to 56 bytes */ - memset( dataPtr, 0, count - 8 ); + lp = shsInfo->data + count / 4; + switch (count % 4) { + case 3: + *lp++ |= (LONG) 0x80; + break; + case 2: + *lp++ |= (LONG) 0x80 << 8; + break; + case 1: + *lp++ |= (LONG) 0x80 << 16; + break; + case 0: + *lp++ = (LONG) 0x80 << 24; + } + if (lp > shsInfo->data + 14) { + /* Pad out to 64 bytes if not enough room for length words */ + *lp = 0; + SHSTransform(shsInfo->digest, shsInfo->data); + lp = shsInfo->data; + } + /* Pad out to 56 bytes */ + while (lp < shsInfo->data + 14) + *lp++ = 0; /* Append length in bits and transform */ - shsInfo->data[ 14 ] = shsInfo->countHi; - shsInfo->data[ 15 ] = shsInfo->countLo; - - longReverse( shsInfo->data, SHS_DATASIZE - 8 ); - SHSTransform( shsInfo->digest, shsInfo->data ); + *lp++ = shsInfo->countHi; + *lp++ = shsInfo->countLo; + SHSTransform(shsInfo->digest, shsInfo->data); } diff --git a/src/lib/crypto/sha/t_shs.c b/src/lib/crypto/sha/t_shs.c index 87d8a0f9d..da55992ec 100644 --- a/src/lib/crypto/sha/t_shs.c +++ b/src/lib/crypto/sha/t_shs.c @@ -32,12 +32,24 @@ static int compareSHSresults(shsInfo, shsTestLevel) SHS_INFO *shsInfo; int shsTestLevel; { - int i; + int i, fail = 0; /* Compare the returned digest and required values */ for( i = 0; i < 5; i++ ) if( shsInfo->digest[ i ] != shsTestResults[ shsTestLevel ][ i ] ) - return( -1 ); + fail = 1; + if (fail) { + printf("\nExpected: "); + for (i = 0; i < 5; i++) { + printf("%8.8lx ", shsTestResults[shsTestLevel][i]); + } + printf("\nGot: "); + for (i = 0; i < 5; i++) { + printf("%8.8lx ", shsInfo->digest[i]); + } + printf("\n"); + return( -1 ); + } return( 0 ); }