From 8a6c38e335789860f4adc42c3ff2c9be92d34bfa Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Mon, 21 Sep 1998 21:33:13 +0000 Subject: [PATCH] restore accidentally deleted files git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10928 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/crypto/sha/.Sanitize | 42 ++++ src/lib/crypto/sha/ChangeLog | 89 ++++++++ src/lib/crypto/sha/Makefile.in | 43 ++++ src/lib/crypto/sha/hmac_sha.c | 101 ++++++++ src/lib/crypto/sha/sha_crypto.c | 76 +++++++ src/lib/crypto/sha/sha_glue.c | 97 ++++++++ src/lib/crypto/sha/shs.c | 392 ++++++++++++++++++++++++++++++++ src/lib/crypto/sha/shs.h | 59 +++++ src/lib/crypto/sha/t_shs.c | 132 +++++++++++ 9 files changed, 1031 insertions(+) create mode 100644 src/lib/crypto/sha/.Sanitize create mode 100644 src/lib/crypto/sha/ChangeLog create mode 100644 src/lib/crypto/sha/Makefile.in create mode 100644 src/lib/crypto/sha/hmac_sha.c create mode 100644 src/lib/crypto/sha/sha_crypto.c create mode 100644 src/lib/crypto/sha/sha_glue.c create mode 100644 src/lib/crypto/sha/shs.c create mode 100644 src/lib/crypto/sha/shs.h create mode 100644 src/lib/crypto/sha/t_shs.c diff --git a/src/lib/crypto/sha/.Sanitize b/src/lib/crypto/sha/.Sanitize new file mode 100644 index 000000000..886bb2b0a --- /dev/null +++ b/src/lib/crypto/sha/.Sanitize @@ -0,0 +1,42 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +.cvsignore +ChangeLog +Makefile.in +configure +configure.in +sha_crypto.c +sha_glue.c +shs.c +shs.h +hmac_sha.c +t_shs.c + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/src/lib/crypto/sha/ChangeLog b/src/lib/crypto/sha/ChangeLog new file mode 100644 index 000000000..19abbbf6e --- /dev/null +++ b/src/lib/crypto/sha/ChangeLog @@ -0,0 +1,89 @@ +Wed Feb 18 16:09:05 1998 Tom Yu + + * Makefile.in: Remove trailing slash from thisconfigdir. Fix up + BUILDTOP for new conventions. + +Fri Feb 13 15:20:54 1998 Theodore Ts'o + + * Makefile.in (thisconfigdir), configure.in: Point the + configuration directory at our parent, and remove our + local configure.in + +Mon Feb 2 17:02:29 1998 Theodore Ts'o + + * Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile + +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 + win-post.in + +Thu Jan 30 21:31:39 1997 Richard Basch + + * sha_crypto.c sha_glue.c: + Declare the functions to take const args where possible + Remove extra includes + + * sha_crypto.c: Function prototypes did not match function names. + +Thu Nov 21 00:58:04 EST 1996 Richard Basch + + * Makefile.in: Win32 build fixed + +Sun Dec 29 21:56:35 1996 Tom Yu + + * Makefile.in: + * configure.in: Update to use new library build procedure. + +Wed Aug 28 17:40:53 1996 Theodore Ts'o + + * shs.c: Only include sys/types.h if present. + + * configure.in: Check for sys/types.h + +Thu Jun 13 10:54:27 1996 Ezra Peisach + + * hmac_sha.c: Include string.h for memcpy prototype + +Sat Jun 8 07:44:35 1996 Ezra Peisach (epeisach@mit.edu) + + * shs.c (longReverse): Test for big vs little endian failed for + little endian machines. + +Thu Jun 6 15:43:26 1996 Theodore Y. Ts'o + + * shs.c (longReverse): Don't use htonl(); it doesn't exist under + Windows. Instead do the test by casting a pointer to an + integer to a char *. + +Mon May 20 17:15:32 1996 Theodore Y. Ts'o + + * t_shs.c (main): Don't do timing tests; it takes too long! + +Tue May 14 17:09:36 1996 Richard Basch + + * .Sanitize: reflect current files + * Makefile.in: added hmac-sha + * hmac_sha.c: implement HMAC-SHA + * sha_crypto.c: use hmac-sha + * sha_glue.c: sanity check the passed in checksum length + * shs.h: replaced sha-des3 with hmac-sha + +Fri May 10 11:19:53 1996 Ezra Peisach + + * shs.c (longReverse): Remove extraneous \. + (expand): Start #define in first column. + +Fri May 10 01:19:18 1996 Richard Basch + + * Makefile.in configure.in t_shs.c sha_glue.c sha_crypto.c shs.c shs.h: + Initial check-in of the functions to support the NIST FIPS 180 + SHA algorithm. Provide interfaces for cksum-sha, cksum-sha-des3. + (enctype-des3-sha is also being defined) diff --git a/src/lib/crypto/sha/Makefile.in b/src/lib/crypto/sha/Makefile.in new file mode 100644 index 000000000..058ac0db0 --- /dev/null +++ b/src/lib/crypto/sha/Makefile.in @@ -0,0 +1,43 @@ +thisconfigdir=./.. +BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U) +CFLAGS = $(CCOPTS) $(DEFS) -I$(srcdir)/../des + +##DOS##BUILDTOP = ..\..\.. +##DOS##PREFIXDIR=sha +##DOS##OBJFILE=..\sha.lst +##WIN16##LIBNAME=..\crypto.lib + +STLIBOBJS=shs.o hmac_sha.o sha_crypto.o sha_glue.o + +OBJS= shs.$(OBJEXT) \ + hmac_sha.$(OBJEXT) \ + sha_crypto.$(OBJEXT) \ + sha_glue.$(OBJEXT) + +SRCS= $(srcdir)/shs.c \ + $(srcdir)/hmac_sha.c \ + $(srcdir)/sha_crypto.c \ + $(srcdir)/sha_glue.c + + +##DOS##LIBOBJS = $(OBJS) + + +all-unix:: all-libobjs + +t_shs: t_shs.o shs.o + $(CC) $(CFLAGS) $(LDFLAGS) -o t_shs t_shs.o shs.o + +t_shs.exe: + $(CC) $(CFLAGS2) -o t_shs.exe t_shs.c shs.c + +check-unix:: t_shs + $(C)t_shs -x + +check-windows:: t_shs$(EXEEXT) + $(C)t_shs$(EXEEXT) -x + +clean:: + $(RM) t_shs$(EXEEXT) t_shs.$(OBJEXT) + +clean-unix:: clean-libobjs diff --git a/src/lib/crypto/sha/hmac_sha.c b/src/lib/crypto/sha/hmac_sha.c new file mode 100644 index 000000000..d57092e69 --- /dev/null +++ b/src/lib/crypto/sha/hmac_sha.c @@ -0,0 +1,101 @@ +#include +#include "shs.h" + +#define PAD_SZ 64 + + +krb5_error_code +hmac_sha(text, text_len, key, key_len, digest) + krb5_octet * text; /* pointer to data stream */ + int text_len; /* length of data stream */ + krb5_octet * key; /* pointer to authentication key */ + int key_len; /* length of authentication key */ + krb5_octet * digest; /* caller digest to be filled in */ +{ + SHS_INFO context; + 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=SHA(key) */ + if (key_len > sizeof(k_ipad)) { + shsInit(&context); + shsUpdate(&context, key, key_len); + shsFinal(&context); + + 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; + } + + /* + * the HMAC_SHA transform looks like: + * + * SHA(K XOR opad, SHA(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memset(k_ipad, 0x36, sizeof(k_ipad)); + memset(k_opad, 0x5c, sizeof(k_opad)); + + /* XOR key with ipad and opad values */ + for (i = 0; i < key_len; i++) { + k_ipad[i] ^= key[i]; + k_opad[i] ^= key[i]; + } + + /* + * perform inner SHA + */ + shsInit(&context); + shsUpdate(&context, k_ipad, sizeof(k_ipad)); + shsUpdate(&context, text, text_len); + shsFinal(&context); + + 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 + */ + shsInit(&context); + shsUpdate(&context, k_opad, sizeof(k_opad)); + shsUpdate(&context, digest, SHS_DIGESTSIZE); + shsFinal(&context); + + 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_crypto.c b/src/lib/crypto/sha/sha_crypto.c new file mode 100644 index 000000000..b539b1199 --- /dev/null +++ b/src/lib/crypto/sha/sha_crypto.c @@ -0,0 +1,76 @@ +#include "shs.h" + +/* Windows needs to these prototypes for the assignment below */ + +static krb5_error_code +krb5_sha_crypto_sum_func + PROTOTYPE((krb5_const krb5_pointer in, + krb5_const size_t in_length, + krb5_const krb5_pointer seed, + krb5_const size_t seed_length, + krb5_checksum FAR *outcksum)); + +static krb5_error_code +krb5_sha_crypto_verify_func + PROTOTYPE((krb5_const krb5_checksum FAR *cksum, + krb5_const krb5_pointer in, + krb5_const size_t in_length, + krb5_const krb5_pointer seed, + krb5_const size_t seed_length)); + +static krb5_error_code +krb5_sha_crypto_sum_func(in, in_length, seed, seed_length, outcksum) + krb5_const krb5_pointer in; + krb5_const size_t in_length; + krb5_const krb5_pointer seed; + krb5_const size_t seed_length; + krb5_checksum FAR *outcksum; +{ + krb5_error_code retval; + + if (outcksum->length < HMAC_SHA_CKSUM_LENGTH) + return KRB5_BAD_MSIZE; + + outcksum->checksum_type = CKSUMTYPE_HMAC_SHA; + outcksum->length = HMAC_SHA_CKSUM_LENGTH; + + retval = hmac_sha(in, in_length, seed, seed_length, outcksum->contents); + return retval; +} + +static krb5_error_code +krb5_sha_crypto_verify_func(cksum, in, in_length, seed, seed_length) + krb5_const krb5_checksum FAR *cksum; + krb5_const krb5_pointer in; + krb5_const size_t in_length; + krb5_const krb5_pointer seed; + krb5_const size_t seed_length; +{ + krb5_octet digest[HMAC_SHA_CKSUM_LENGTH]; + krb5_error_code retval; + + if (cksum->checksum_type != CKSUMTYPE_HMAC_SHA) + return KRB5KRB_AP_ERR_INAPP_CKSUM; + if (cksum->length != HMAC_SHA_CKSUM_LENGTH) + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + + retval = hmac_sha(in, in_length, seed, seed_length, digest); + if (retval) goto cleanup; + + if (memcmp((char *)digest, (char *)cksum->contents, cksum->length)) + retval = KRB5KRB_AP_ERR_BAD_INTEGRITY; + +cleanup: + memset((char *)digest, 0, sizeof(digest)); + return retval; +} + +krb5_checksum_entry hmac_sha_cksumtable_entry = +{ + 0, + krb5_sha_crypto_sum_func, + krb5_sha_crypto_verify_func, + HMAC_SHA_CKSUM_LENGTH, + 1, /* is collision proof */ + 1, /* uses key */ +}; diff --git a/src/lib/crypto/sha/sha_glue.c b/src/lib/crypto/sha/sha_glue.c new file mode 100644 index 000000000..58a93b723 --- /dev/null +++ b/src/lib/crypto/sha/sha_glue.c @@ -0,0 +1,97 @@ +#include "shs.h" + +krb5_error_code +krb5_sha_sum_func + PROTOTYPE((krb5_const krb5_pointer in, + krb5_const size_t in_length, + krb5_const krb5_pointer seed, + krb5_const size_t seed_length, + krb5_checksum FAR *outcksum)); + +krb5_error_code +krb5_sha_verify_func + PROTOTYPE((krb5_const krb5_checksum FAR *cksum, + krb5_const krb5_pointer in, + krb5_const size_t in_length, + krb5_const krb5_pointer seed, + krb5_const size_t seed_length)); + +krb5_error_code +krb5_sha_sum_func(in, in_length, seed, seed_length, outcksum) + krb5_const krb5_pointer in; + krb5_const size_t in_length; + krb5_const krb5_pointer seed; + krb5_const size_t seed_length; + krb5_checksum FAR *outcksum; +{ + krb5_octet *input = (krb5_octet *)in; + krb5_octet *cp; + LONG *lp; + SHS_INFO working; + + if (outcksum->length < SHS_DIGESTSIZE) + return KRB5_BAD_MSIZE; + + shsInit(&working); + shsUpdate(&working, input, in_length); + shsFinal(&working); + + outcksum->checksum_type = CKSUMTYPE_NIST_SHA; + outcksum->length = SHS_DIGESTSIZE; + + 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; +} + +krb5_error_code +krb5_sha_verify_func(cksum, in, in_length, seed, seed_length) + krb5_const krb5_checksum FAR *cksum; + krb5_const krb5_pointer in; + krb5_const size_t in_length; + krb5_const krb5_pointer seed; + krb5_const size_t 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; + if (cksum->length != SHS_DIGESTSIZE) + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + + shsInit(&working); + shsUpdate(&working, input, in_length); + shsFinal(&working); + + retval = 0; + 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; +} + +krb5_checksum_entry nist_sha_cksumtable_entry = { + 0, + krb5_sha_sum_func, + krb5_sha_verify_func, + SHS_DIGESTSIZE, + 1, /* is collision proof */ + 0, /* doesn't use key */ +}; diff --git a/src/lib/crypto/sha/shs.c b/src/lib/crypto/sha/shs.c new file mode 100644 index 000000000..e18f3af9e --- /dev/null +++ b/src/lib/crypto/sha/shs.c @@ -0,0 +1,392 @@ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include +#include "shs.h" + +/* The SHS f()-functions. The f1 and f3 functions can be optimized to + save one boolean operation each - thanks to Rich Schroeppel, + rcs@cs.arizona.edu for discovering this */ + +#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */ +#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ +#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */ +#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */ + +/* The SHS Mysterious Constants */ + +#define K1 0x5A827999L /* Rounds 0-19 */ +#define K2 0x6ED9EBA1L /* Rounds 20-39 */ +#define K3 0x8F1BBCDCL /* Rounds 40-59 */ +#define K4 0xCA62C1D6L /* Rounds 60-79 */ + +/* SHS initial values */ + +#define h0init 0x67452301L +#define h1init 0xEFCDAB89L +#define h2init 0x98BADCFEL +#define h3init 0x10325476L +#define h4init 0xC3D2E1F0L + +/* Note that it may be necessary to add parentheses to these macros if they + are to be called with expressions as arguments */ + +/* 32-bit rotate left - kludged with shifts */ + +#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 + data, and the remaining 64 are defined by + + W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ] + + This implementation generates these values on the fly in a circular + buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this + optimization. + + The updated SHS changes the expanding function by adding a rotate of 1 + bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor + for this information */ + +#ifdef NEW_SHS +#define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \ + W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ))) +#else +#define expand(W,i) ( W[ i & 15 ] ^= W[ (i - 14) & 15 ] ^ \ + W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) +#endif /* NEW_SHS */ + +/* The prototype SHS sub-round. The fundamental sub-round is: + + a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data; + b' = a; + c' = ROTL( 30, b ); + d' = c; + e' = d; + + but this is implemented by unrolling the loop 5 times and renaming the + variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration. + This code is then replicated 20 times for each of the 4 functions, using + 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, \ + e &= 0xffffffff, b = ROTL( 30, b ) ) + +/* Initialize the SHS values */ + +void shsInit(shsInfo) + SHS_INFO *shsInfo; +{ + /* Set the h-vars to their initial values */ + shsInfo->digest[ 0 ] = h0init; + shsInfo->digest[ 1 ] = h1init; + shsInfo->digest[ 2 ] = h2init; + shsInfo->digest[ 3 ] = h3init; + shsInfo->digest[ 4 ] = h4init; + + /* Initialise bit count */ + shsInfo->countLo = shsInfo->countHi = 0; +} + +/* Perform the SHS transformation. Note that this code, like MD5, seems to + break some optimizing compilers due to the complexity of the expressions + and the size of the basic block. It may be necessary to split it into + sections, e.g. based on the four subrounds + + Note that this corrupts the shsInfo->data area */ + +static void SHSTransform KRB5_PROTOTYPE((LONG *digest, LONG *data)); + +static +void SHSTransform(digest, data) + LONG *digest; + LONG *data; +{ + LONG A, B, C, D, E; /* Local vars */ + LONG eData[ 16 ]; /* Expanded data */ + + /* Set up first buffer and local data buffer */ + A = digest[ 0 ]; + B = digest[ 1 ]; + C = digest[ 2 ]; + D = digest[ 3 ]; + E = digest[ 4 ]; + 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 ] ); + subRound( E, A, B, C, D, f1, K1, eData[ 1 ] ); + subRound( D, E, A, B, C, f1, K1, eData[ 2 ] ); + subRound( C, D, E, A, B, f1, K1, eData[ 3 ] ); + subRound( B, C, D, E, A, f1, K1, eData[ 4 ] ); + subRound( A, B, C, D, E, f1, K1, eData[ 5 ] ); + subRound( E, A, B, C, D, f1, K1, eData[ 6 ] ); + subRound( D, E, A, B, C, f1, K1, eData[ 7 ] ); + subRound( C, D, E, A, B, f1, K1, eData[ 8 ] ); + subRound( B, C, D, E, A, f1, K1, eData[ 9 ] ); + subRound( A, B, C, D, E, f1, K1, eData[ 10 ] ); + subRound( E, A, B, C, D, f1, K1, eData[ 11 ] ); + subRound( D, E, A, B, C, f1, K1, eData[ 12 ] ); + subRound( C, D, E, A, B, f1, K1, eData[ 13 ] ); + subRound( B, C, D, E, A, f1, K1, eData[ 14 ] ); + subRound( A, B, C, D, E, f1, K1, eData[ 15 ] ); + subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) ); + subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) ); + subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) ); + subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) ); + + subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) ); + subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) ); + subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) ); + subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) ); + subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) ); + subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) ); + subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) ); + subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) ); + subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) ); + subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) ); + subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) ); + subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) ); + subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) ); + subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) ); + subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) ); + subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) ); + subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) ); + subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) ); + subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) ); + subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) ); + + subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) ); + subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) ); + subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) ); + subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) ); + subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) ); + subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) ); + subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) ); + subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) ); + subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) ); + subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) ); + subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) ); + subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) ); + subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) ); + subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) ); + subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) ); + subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) ); + subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) ); + subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) ); + subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) ); + subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) ); + + subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) ); + subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) ); + subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) ); + subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) ); + subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) ); + subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) ); + subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) ); + subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) ); + subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) ); + subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) ); + subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) ); + subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) ); + subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) ); + subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) ); + subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) ); + subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) ); + subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) ); + subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) ); + subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) ); + subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) ); + + /* 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 + array of longwords. It is possible to make the code endianness- + independant by fiddling around with data at the byte level, but this + makes for very slow code, so we rely on the user to sort out endianness + at compile time */ + +void longReverse( LONG *buffer, int byteCount ) +{ + LONG value; + static int init = 0; + char *cp; + + switch (init) { + case 0: + init=1; + cp = (char *) &init; + if (*cp == 1) { + init=2; + break; + } + init=1; + /* fall through - MSB */ + case 1: + return; + } + + byteCount /= sizeof( LONG ); + while( byteCount-- ) { + value = *buffer; + value = ( ( value & 0xFF00FF00L ) >> 8 ) | + ( ( value & 0x00FF00FFL ) << 8 ); + *buffer++ = ( value << 16 ) | ( value >> 16 ); + } +} + +/* Update SHS for a block of data */ + +void shsUpdate(shsInfo, buffer, count) + SHS_INFO *shsInfo; + BYTE *buffer; + int count; +{ + LONG tmp; + int dataCount, canfill; + LONG *lp; + + /* Update bitcount */ + tmp = shsInfo->countLo; + 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; + + /* Handle any leading odd-sized chunks */ + 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) { + 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 + 1 0* (64-bit count of bits processed, MSB-first) */ + +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; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + 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 */ + *lp++ = shsInfo->countHi; + *lp++ = shsInfo->countLo; + SHSTransform(shsInfo->digest, shsInfo->data); +} diff --git a/src/lib/crypto/sha/shs.h b/src/lib/crypto/sha/shs.h new file mode 100644 index 000000000..01acddb82 --- /dev/null +++ b/src/lib/crypto/sha/shs.h @@ -0,0 +1,59 @@ +#ifndef _SHS_DEFINED + +#include + +#define _SHS_DEFINED + +/* Some useful types */ + +typedef krb5_octet BYTE; + +/* Old DOS/Windows compilers are case-insensitive */ +#if !defined(_MSDOS) && !defined(_WIN32) +typedef krb5_ui_4 LONG; +#endif + + +/* Define the following to use the updated SHS implementation */ +#define NEW_SHS /**/ + +/* The SHS block size and message digest sizes, in bytes */ + +#define SHS_DATASIZE 64 +#define SHS_DIGESTSIZE 20 + +/* The structure for storing SHS info */ + +typedef struct { + LONG digest[ 5 ]; /* Message digest */ + LONG countLo, countHi; /* 64-bit bit count */ + LONG data[ 16 ]; /* SHS data buffer */ + } SHS_INFO; + +/* Message digest functions (shs.c) */ +void shsInit + KRB5_PROTOTYPE((SHS_INFO *shsInfo)); +void shsUpdate + KRB5_PROTOTYPE((SHS_INFO *shsInfo, BYTE *buffer, int count)); +void shsFinal + KRB5_PROTOTYPE((SHS_INFO *shsInfo)); + + +/* Keyed Message digest functions (hmac_sha.c) */ +krb5_error_code hmac_sha + KRB5_PROTOTYPE((krb5_octet *text, + int text_len, + krb5_octet *key, + int key_len, + krb5_octet *digest)); + + +#define NIST_SHA_CKSUM_LENGTH SHS_DIGESTSIZE +#define HMAC_SHA_CKSUM_LENGTH SHS_DIGESTSIZE + + +extern krb5_checksum_entry + nist_sha_cksumtable_entry, + hmac_sha_cksumtable_entry; + +#endif /* _SHS_DEFINED */ diff --git a/src/lib/crypto/sha/t_shs.c b/src/lib/crypto/sha/t_shs.c new file mode 100644 index 000000000..da55992ec --- /dev/null +++ b/src/lib/crypto/sha/t_shs.c @@ -0,0 +1,132 @@ +/**************************************************************************** +* * +* SHS Test Code * +* * +****************************************************************************/ + +#include +#include +#include +#include "shs.h" + +/* Test the SHS implementation */ + +#ifdef NEW_SHS + +static LONG shsTestResults[][ 5 ] = { + { 0xA9993E36L, 0x4706816AL, 0xBA3E2571L, 0x7850C26CL, 0x9CD0D89DL, }, + { 0x84983E44L, 0x1C3BD26EL, 0xBAAE4AA1L, 0xF95129E5L, 0xE54670F1L, }, + { 0x34AA973CL, 0xD4C4DAA4L, 0xF61EEB2BL, 0xDBAD2731L, 0x6534016FL, } + }; + +#else + +static LONG shsTestResults[][ 5 ] = { + { 0x0164B8A9L, 0x14CD2A5EL, 0x74C4F7FFL, 0x082C4D97L, 0xF1EDF880L }, + { 0xD2516EE1L, 0xACFA5BAFL, 0x33DFC1C4L, 0x71E43844L, 0x9EF134C8L }, + { 0x3232AFFAL, 0x48628A26L, 0x653B5AAAL, 0x44541FD9L, 0x0D690603L } + }; +#endif /* NEW_SHS */ + +static int compareSHSresults(shsInfo, shsTestLevel) +SHS_INFO *shsInfo; +int shsTestLevel; +{ + int i, fail = 0; + + /* Compare the returned digest and required values */ + for( i = 0; i < 5; i++ ) + if( shsInfo->digest[ i ] != shsTestResults[ shsTestLevel ][ i ] ) + 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 ); +} + +main() +{ + SHS_INFO shsInfo; + unsigned int i; + time_t secondCount; + BYTE data[ 200 ]; + + /* Make sure we've got the endianness set right. If the machine is + big-endian (up to 64 bits) the following value will be signed, + otherwise it will be unsigned. Unfortunately we can't test for odd + things like middle-endianness without knowing the size of the data + types */ + + /* Test SHS against values given in SHS standards document */ + printf( "Running SHS test 1 ... " ); + shsInit( &shsInfo ); + shsUpdate( &shsInfo, ( BYTE * ) "abc", 3 ); + shsFinal( &shsInfo ); + if( compareSHSresults( &shsInfo, 0 ) == -1 ) + { + putchar( '\n' ); + puts( "SHS test 1 failed" ); + exit( -1 ); + } +#ifdef NEW_SHS + puts( "passed, result= A9993E364706816ABA3E25717850C26C9CD0D89D" ); +#else + puts( "passed, result= 0164B8A914CD2A5E74C4F7FF082C4D97F1EDF880" ); +#endif /* NEW_SHS */ + + printf( "Running SHS test 2 ... " ); + shsInit( &shsInfo ); + shsUpdate( &shsInfo, ( BYTE * ) "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56 ); + shsFinal( &shsInfo ); + if( compareSHSresults( &shsInfo, 1 ) == -1 ) + { + putchar( '\n' ); + puts( "SHS test 2 failed" ); + exit( -1 ); + } +#ifdef NEW_SHS + puts( "passed, result= 84983E441C3BD26EBAAE4AA1F95129E5E54670F1" ); +#else + puts( "passed, result= D2516EE1ACFA5BAF33DFC1C471E438449EF134C8" ); +#endif /* NEW_SHS */ + + printf( "Running SHS test 3 ... " ); + shsInit( &shsInfo ); + for( i = 0; i < 15625; i++ ) + shsUpdate( &shsInfo, ( BYTE * ) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 64 ); + shsFinal( &shsInfo ); + if( compareSHSresults( &shsInfo, 2 ) == -1 ) + { + putchar( '\n' ); + puts( "SHS test 3 failed" ); + exit( -1 ); + } +#ifdef NEW_SHS + puts( "passed, result= 34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" ); +#else + puts( "passed, result= 3232AFFA48628A26653B5AAA44541FD90D690603" ); +#endif /* NEW_SHS */ + +#if 0 + printf( "\nTesting speed for 100MB data... " ); + shsInit( &shsInfo ); + secondCount = time( NULL ); + for( i = 0; i < 500000U; i++ ) + shsUpdate( &shsInfo, data, 200 ); + secondCount = time( NULL ) - secondCount; + printf( "done. Time = %ld seconds, %ld kbytes/second.\n", \ + secondCount, 100500L / secondCount ); +#endif + + puts( "\nAll SHS tests passed" ); + exit( 0 ); +} -- 2.26.2