123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- /* --------------------------------- SHA.C ------------------------------- */
- #include <string.h>
- #include "sha.h"
- /*
- * NIST Secure Hash Algorithm.
- *
- * Written 2 September 1992, Peter C. Gutmann.
- * This implementation placed in the public domain.
- *
- * Modified 1 June 1993, Colin Plumb.
- * Modified for the new SHS based on Peter Gutmann's work,
- * 18 July 1994, Colin Plumb.
- * Gutmann's work.
- * Renamed to SHA and comments updated a bit 1 November 1995, Colin Plumb.
- * These modifications placed in the public domain.
- *
- * Comments to pgut1@cs.aukuni.ac.nz
- */
- #include <string.h>
- /*
- * The SHA 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) ( (x & y) | (~x & z) ) // Rounds 0-19 */
- #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) | (x & z) | (y & z) ) // Rounds 40-59 */
- #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 SHA Mysterious Constants.
- * K1 = floor(sqrt(2) * 2^30)
- * K2 = floor(sqrt(3) * 2^30)
- * K3 = floor(sqrt(5) * 2^30)
- * K4 = floor(sqrt(10) * 2^30)
- */
- #define K1 0x5A827999L /* Rounds 0-19 */
- #define K2 0x6ED9EBA1L /* Rounds 20-39 */
- #define K3 0x8F1BBCDCL /* Rounds 40-59 */
- #define K4 0xCA62C1D6L /* Rounds 60-79 */
- /* SHA 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) | (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.
- */
- #if SHA_VERSION
- /* The new ("corrected") SHA, FIPS 180.1 */
- /* Same as below, but then rotate left one bit */
- #define expand(W,i) (W[i&15] ^= W[(i-14)&15] ^ W[(i-8)&15] ^ W[(i-3)&15], \
- W[i&15] = ROTL(1, W[i&15]))
- #else
- /* The old (pre-correction) SHA, FIPS 180 */
- #define expand(W,i) (W[i&15] ^= W[(i-14)&15] ^ W[(i-8)&15] ^ W[(i-3)&15])
- #endif
- /*
- * The prototype SHA 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.
- */
- #define subRound(a, b, c, d, e, f, k, data) \
- ( e += ROTL(5,a) + f(b, c, d) + k + data, b = ROTL(30, b) )
- /*
- * The above code is replicated 20 times for each of the 4 functions,
- * using the next 20 values from the W[] array each time.
- */
- /* Initialize the SHA values */
- void
- shaInit(struct SHAContext *sha)
- {
- /* Set the h-vars to their initial values */
- sha->digest[0] = h0init;
- sha->digest[1] = h1init;
- sha->digest[2] = h2init;
- sha->digest[3] = h3init;
- sha->digest[4] = h4init;
- /* Initialise bit count */
- #ifdef HAVE64
- sha->count = 0;
- #else
- sha->countLo = sha->countHi = 0;
- #endif
- }
- /*
- * Perform the SHA 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 sha->data area.
- */
- #ifndef ASM
- void shaTransform(struct SHAContext *sha)
- {
- register word32 A, B, C, D, E;
- /* Set up first buffer */
- A = sha->digest[0];
- B = sha->digest[1];
- C = sha->digest[2];
- D = sha->digest[3];
- E = sha->digest[4];
- /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
- subRound( A, B, C, D, E, f1, K1, sha->data[ 0] );
- subRound( E, A, B, C, D, f1, K1, sha->data[ 1] );
- subRound( D, E, A, B, C, f1, K1, sha->data[ 2] );
- subRound( C, D, E, A, B, f1, K1, sha->data[ 3] );
- subRound( B, C, D, E, A, f1, K1, sha->data[ 4] );
- subRound( A, B, C, D, E, f1, K1, sha->data[ 5] );
- subRound( E, A, B, C, D, f1, K1, sha->data[ 6] );
- subRound( D, E, A, B, C, f1, K1, sha->data[ 7] );
- subRound( C, D, E, A, B, f1, K1, sha->data[ 8] );
- subRound( B, C, D, E, A, f1, K1, sha->data[ 9] );
- subRound( A, B, C, D, E, f1, K1, sha->data[10] );
- subRound( E, A, B, C, D, f1, K1, sha->data[11] );
- subRound( D, E, A, B, C, f1, K1, sha->data[12] );
- subRound( C, D, E, A, B, f1, K1, sha->data[13] );
- subRound( B, C, D, E, A, f1, K1, sha->data[14] );
- subRound( A, B, C, D, E, f1, K1, sha->data[15] );
- subRound( E, A, B, C, D, f1, K1, expand(sha->data, 16) );
- subRound( D, E, A, B, C, f1, K1, expand(sha->data, 17) );
- subRound( C, D, E, A, B, f1, K1, expand(sha->data, 18) );
- subRound( B, C, D, E, A, f1, K1, expand(sha->data, 19) );
- subRound( A, B, C, D, E, f2, K2, expand(sha->data, 20) );
- subRound( E, A, B, C, D, f2, K2, expand(sha->data, 21) );
- subRound( D, E, A, B, C, f2, K2, expand(sha->data, 22) );
- subRound( C, D, E, A, B, f2, K2, expand(sha->data, 23) );
- subRound( B, C, D, E, A, f2, K2, expand(sha->data, 24) );
- subRound( A, B, C, D, E, f2, K2, expand(sha->data, 25) );
- subRound( E, A, B, C, D, f2, K2, expand(sha->data, 26) );
- subRound( D, E, A, B, C, f2, K2, expand(sha->data, 27) );
- subRound( C, D, E, A, B, f2, K2, expand(sha->data, 28) );
- subRound( B, C, D, E, A, f2, K2, expand(sha->data, 29) );
- subRound( A, B, C, D, E, f2, K2, expand(sha->data, 30) );
- subRound( E, A, B, C, D, f2, K2, expand(sha->data, 31) );
- subRound( D, E, A, B, C, f2, K2, expand(sha->data, 32) );
- subRound( C, D, E, A, B, f2, K2, expand(sha->data, 33) );
- subRound( B, C, D, E, A, f2, K2, expand(sha->data, 34) );
- subRound( A, B, C, D, E, f2, K2, expand(sha->data, 35) );
- subRound( E, A, B, C, D, f2, K2, expand(sha->data, 36) );
- subRound( D, E, A, B, C, f2, K2, expand(sha->data, 37) );
- subRound( C, D, E, A, B, f2, K2, expand(sha->data, 38) );
- subRound( B, C, D, E, A, f2, K2, expand(sha->data, 39) );
- subRound( A, B, C, D, E, f3, K3, expand(sha->data, 40) );
- subRound( E, A, B, C, D, f3, K3, expand(sha->data, 41) );
- subRound( D, E, A, B, C, f3, K3, expand(sha->data, 42) );
- subRound( C, D, E, A, B, f3, K3, expand(sha->data, 43) );
- subRound( B, C, D, E, A, f3, K3, expand(sha->data, 44) );
- subRound( A, B, C, D, E, f3, K3, expand(sha->data, 45) );
- subRound( E, A, B, C, D, f3, K3, expand(sha->data, 46) );
- subRound( D, E, A, B, C, f3, K3, expand(sha->data, 47) );
- subRound( C, D, E, A, B, f3, K3, expand(sha->data, 48) );
- subRound( B, C, D, E, A, f3, K3, expand(sha->data, 49) );
- subRound( A, B, C, D, E, f3, K3, expand(sha->data, 50) );
- subRound( E, A, B, C, D, f3, K3, expand(sha->data, 51) );
- subRound( D, E, A, B, C, f3, K3, expand(sha->data, 52) );
- subRound( C, D, E, A, B, f3, K3, expand(sha->data, 53) );
- subRound( B, C, D, E, A, f3, K3, expand(sha->data, 54) );
- subRound( A, B, C, D, E, f3, K3, expand(sha->data, 55) );
- subRound( E, A, B, C, D, f3, K3, expand(sha->data, 56) );
- subRound( D, E, A, B, C, f3, K3, expand(sha->data, 57) );
- subRound( C, D, E, A, B, f3, K3, expand(sha->data, 58) );
- subRound( B, C, D, E, A, f3, K3, expand(sha->data, 59) );
- subRound( A, B, C, D, E, f4, K4, expand(sha->data, 60) );
- subRound( E, A, B, C, D, f4, K4, expand(sha->data, 61) );
- subRound( D, E, A, B, C, f4, K4, expand(sha->data, 62) );
- subRound( C, D, E, A, B, f4, K4, expand(sha->data, 63) );
- subRound( B, C, D, E, A, f4, K4, expand(sha->data, 64) );
- subRound( A, B, C, D, E, f4, K4, expand(sha->data, 65) );
- subRound( E, A, B, C, D, f4, K4, expand(sha->data, 66) );
- subRound( D, E, A, B, C, f4, K4, expand(sha->data, 67) );
- subRound( C, D, E, A, B, f4, K4, expand(sha->data, 68) );
- subRound( B, C, D, E, A, f4, K4, expand(sha->data, 69) );
- subRound( A, B, C, D, E, f4, K4, expand(sha->data, 70) );
- subRound( E, A, B, C, D, f4, K4, expand(sha->data, 71) );
- subRound( D, E, A, B, C, f4, K4, expand(sha->data, 72) );
- subRound( C, D, E, A, B, f4, K4, expand(sha->data, 73) );
- subRound( B, C, D, E, A, f4, K4, expand(sha->data, 74) );
- subRound( A, B, C, D, E, f4, K4, expand(sha->data, 75) );
- subRound( E, A, B, C, D, f4, K4, expand(sha->data, 76) );
- subRound( D, E, A, B, C, f4, K4, expand(sha->data, 77) );
- subRound( C, D, E, A, B, f4, K4, expand(sha->data, 78) );
- subRound( B, C, D, E, A, f4, K4, expand(sha->data, 79) );
- /* Build message digest */
- sha->digest[0] += A;
- sha->digest[1] += B;
- sha->digest[2] += C;
- sha->digest[3] += D;
- sha->digest[4] += E;
- }
- #endif /* !ASM */
- /*
- * SHA is defined in big-endian form, so this converts the buffer from
- * bytes to words, independent of the machine's native endianness.
- *
- * Assuming a consistent byte ordering for the machine, this also
- * has the magic property of being self-inverse. It is used as
- * such.
- */
- static void byteReverse(word32 *buffer, unsigned byteCount)
- {
- word32 value;
- byteCount /= sizeof(word32);
- while ( byteCount-- ) {
- value = (word32)((unsigned)((word8 *)buffer)[0] << 8 |
- ((word8 *)buffer)[1]) << 16 |
- ((unsigned)((word8 *)buffer)[2] << 8 |
- ((word8 *)buffer)[3]);
- *buffer++ = value;
- }
- }
- /* Update SHA for a block of data. */
- void
- shaUpdate(struct SHAContext *sha, word8 const *buffer, unsigned count)
- {
- word32 t;
- /* Update bitcount */
- #ifdef HAVE64
- t = (word32)sha->count & 0x3f;
- sha->count += count;
- #else
- t = sha->countLo;
- if ( ( sha->countLo = t + count ) < t )
- sha->countHi++; /* Carry from low to high */
- t &= 0x3f; /* Bytes already in sha->data */
- #endif
- /* Handle any leading odd-sized chunks */
- if (t) {
- word8 *p = (word8 *)sha->data + t;
- t = 64-t;
- if (count < t) {
- memcpy(p, buffer, count);
- return;
- }
- memcpy(p, buffer, t);
- byteReverse(sha->data, SHA_BLOCKSIZE);
- shaTransform(sha);
- buffer += t;
- count -= t;
- }
- /* Process data in SHA_BLOCKSIZE chunks */
- while (count >= SHA_BLOCKSIZE) {
- memcpy(sha->data, buffer, SHA_BLOCKSIZE);
- byteReverse(sha->data, SHA_BLOCKSIZE);
- shaTransform(sha);
- buffer += SHA_BLOCKSIZE;
- count -= SHA_BLOCKSIZE;
- }
- /* Handle any remaining bytes of data. */
- memcpy(sha->data, buffer, count);
- }
- /* Final wrapup - pad to 64-byte boundary with the bit pattern
- 1 0* (64-bit count of bits processed, MSB-first) */
- void
- shaFinal(struct SHAContext *sha, word8 *hash)
- {
- int count;
- word8 *p;
- /* Compute number of bytes mod 64 */
- #ifdef HAVE64
- count = (int)sha->count & 0x3F;
- #else
- count = (int)sha->countLo & 0x3F;
- #endif
- /*
- * Set the first char of padding to 0x80.
- * This is safe since there is always at least one byte free
- */
- p = (word8 *)sha->data + count;
- *p++ = 0x80;
- /* Bytes of padding needed to make 64 bytes */
- count = SHA_BLOCKSIZE - 1 - count;
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
- byteReverse(sha->data, SHA_BLOCKSIZE);
- shaTransform(sha);
- /* Now fill the next block with 56 bytes */
- memset(sha->data, 0, SHA_BLOCKSIZE-8);
- } else {
- /* Pad block to 56 bytes */
- memset(p, 0, count-8);
- }
- byteReverse(sha->data, SHA_BLOCKSIZE-8);
- /* Append length in *bits* and transform */
- #if HAVE64
- sha->data[14] = (word32)(sha->count >> 29);
- sha->data[15] = (word32)sha->count << 3;
- #else
- sha->data[14] = sha->countHi << 3 | sha->countLo >> 29;
- sha->data[15] = sha->countLo << 3;
- #endif
- shaTransform(sha);
- /* Store output hash in buffer */
- byteReverse(sha->digest, SHA_DIGESTSIZE);
- memcpy(hash, sha->digest, SHA_DIGESTSIZE);
- memset(sha, 0, sizeof(*sha));
- }
- #if 0
- /* ----------------------------- SHA Test code --------------------------- */
- #include <stdio.h>
- #include <stdlib.h> /* For exit() */
- #include <time.h>
- /* Size of buffer for SHA speed test data */
- #define TEST_BLOCK_SIZE ( SHA_DIGESTSIZE * 100 )
- /* Number of bytes of test data to process */
- #define TEST_BYTES 10000000L
- #define TEST_BLOCKS ( TEST_BYTES / TEST_BLOCK_SIZE )
- #if SHA_VERSION
- static char const *shaTestResults[] = {
- "A9993E364706816ABA3E25717850C26C9CD0D89D",
- "84983E441C3BD26EBAAE4AA1F95129E5E54670F1",
- "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F",
- "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F",
- "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" };
- #else
- static char const *shaTestResults[] = {
- "0164B8A914CD2A5E74C4F7FF082C4D97F1EDF880",
- "D2516EE1ACFA5BAF33DFC1C471E438449EF134C8",
- "3232AFFA48628A26653B5AAA44541FD90D690603",
- "3232AFFA48628A26653B5AAA44541FD90D690603",
- "3232AFFA48628A26653B5AAA44541FD90D690603" };
- #endif
- static int
- compareSHAresults(word8 *hash, int level)
- {
- char buf[41];
- int i;
- for (i = 0; i < SHA_DIGESTSIZE; i++)
- sprintf(buf+2*i, "%02X", hash[i]);
- if (strcmp(buf, shaTestResults[level-1]) == 0) {
- printf("Test %d passed, result = %s\n", level, buf);
- return 0;
- } else {
- printf("Error in SHA implementation: Test %d failed\n", level);
- printf(" Result = %s\n", buf);
- printf("Expected = %s\n", shaTestResults[level-1]);
- return -1;
- }
- }
- int
- main(void)
- {
- struct SHAContext sha;
- word8 data[TEST_BLOCK_SIZE];
- word8 hash[SHA_DIGESTSIZE];
- time_t seconds;
- long i;
- word32 t;
- /* Check that LITTLE_ENDIAN is set correctly */
- t = 0x12345678;
- #if LITTLE_ENDIAN
- if (*(word8 *)&t != 0x78) {
- puts("Error: Define BIG_ENDIAN in SHA.H and recompile");
- exit(-1);
- }
- #elif BIG_ENDIAN
- if (*(word8 *)&t != 0x12) {
- puts("Error: Define LITTLE_ENDIAN in SHA.H and recompile");
- exit(-1);
- }
- #endif
- /*
- * Test output data (these are the only test data given in the
- * Secure Hash Standard document, but chances are if it works
- * for this it'll work for anything)
- */
- shaInit(&sha);
- shaUpdate(&sha, (word8 *)"abc", 3);
- shaFinal(&sha, hash);
- if (compareSHAresults(hash, 1) < 0)
- exit (-1);
- shaInit(&sha);
- shaUpdate(&sha, (word8 *)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56);
- shaFinal(&sha, hash);
- if (compareSHAresults(hash, 2) < 0)
- exit (-1);
- /* 1,000,000 bytes of ASCII 'a' (0x61), by 64's */
- shaInit(&sha);
- for (i = 0; i < 15625; i++)
- shaUpdate(&sha, (word8 *)"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 64);
- shaFinal(&sha, hash);
- if (compareSHAresults(hash, 3) < 0)
- exit (-1);
- /* 1,000,000 bytes of ASCII 'a' (0x61), by 25's */
- shaInit(&sha);
- for (i = 0; i < 40000; i++)
- shaUpdate(&sha, (word8 *)"aaaaaaaaaaaaaaaaaaaaaaaaa", 25);
- shaFinal(&sha, hash);
- if (compareSHAresults(hash, 4) < 0)
- exit (-1);
- /* 1,000,000 bytes of ASCII 'a' (0x61), by 125's */
- shaInit(&sha);
- for (i = 0; i < 8000; i++)
- shaUpdate(&sha, (word8 *)"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 125);
- shaFinal(&sha, hash);
- if (compareSHAresults(hash, 5) < 0)
- exit (-1);
- /* Now perform time trial, generating MD for 10MB of data. First,
- initialize the test data */
- memset(data, 0, TEST_BLOCK_SIZE);
- /* Get start time */
- printf("SHA time trial. Processing %ld characters...\n", TEST_BYTES);
- seconds = time((time_t *)0);
- /* Calculate SHA message digest in TEST_BLOCK_SIZE byte blocks */
- shaInit(&sha);
- for (i = TEST_BLOCKS; i > 0; i--)
- shaUpdate(&sha, data, TEST_BLOCK_SIZE);
- shaFinal(&sha, hash);
- /* Get finish time and print difference */
- seconds = time((time_t *)0) - seconds;
- printf("Seconds to process test input: %ld\n", seconds);
- printf("Characters processed per second: %ld\n", TEST_BYTES / seconds);
- return 0;
- }
- #endif /* Test driver */
|