/* sha.c - Functions to compute the SHA1 hash (message-digest) of files or blocks of memory. Complies to the NIST specification FIPS-180-1. Copyright (C) 2000, 2001, 2003 Scott G. Miller Modified for hackerlab: Copyright (C) 2004 Colin Walters Credits: Robert Klep -- Expansion function fix */ #include "hackerlab/bugs/panic.h" #include "hackerlab/machine/endian.h" #include "hackerlab/mem/mem.h" #include "hackerlab/char/str.h" #include "hackerlab/fmt/cvt.h" #include "hackerlab/hash/sha1.h" /* Not-swap is a macro that does an endian swap on architectures that are big-endian, as SHA needs some data in a little-endian format */ /************************************************************************ *(h1 "SHA1 Routines") * * The SHA1 routines allow you to compute an SHA1 message digest * According to the definition of SHA1 in RFC 3174 from September 2001. * */ /* Structure to save state of computation between the single steps. */ struct sha1_context { sha1_t current_sha1; t_uint32 total[2]; t_uint32 buflen; t_uchar buffer[128]; }; static void sha1_process_blocks (const void *buffer, size_t len, sha1_context_t ctx); #if MACHINE_IS_BIGENDIAN # define NOTSWAP(n) (n) # define SWAP(n) \ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) #else # define NOTSWAP(n) \ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) # define SWAP(n) (n) #endif /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (RFC 1321, 3.1: Step 1) */ static const t_uchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; /*(c make_sha1_context) * sha1_context_t make_sha1_context (alloc_limits limits); * * Allocate and initialize an object which will keep track of the * state of an sha1 digest computation. */ sha1_context_t make_sha1_context (alloc_limits limits) { sha1_context_t ctx = 0; ctx = lim_malloc (limits, sizeof (*ctx)); sha1_context_reset (ctx); return ctx; } /*(c sha1_context_reset) * void sha1_context_reset (sha1_context_t ctx); * * Reinitialize a SHA1 state object. This will * undo the effects of any previous calls to * `sha1_scan'. */ void sha1_context_reset (sha1_context_t ctx) { if (ctx) { ctx->current_sha1.A = 0x67452301; ctx->current_sha1.B = 0xefcdab89; ctx->current_sha1.C = 0x98badcfe; ctx->current_sha1.D = 0x10325476; ctx->current_sha1.E = 0xc3d2e1f0; ctx->total[0] = ctx->total[1] = 0; ctx->buflen = 0; } } /*(c free_sha1_context) * void free_sha1_context (alloc_limits limits, sha1_context_t ctx); * * Free all resources associated with an sha1 state object. */ void free_sha1_context (alloc_limits limits, sha1_context_t ctx) { lim_free (limits, ctx); } /*(c sha1_scan) * void sha1_scan (sha1_context_t hd, t_uchar * inbuf, size_t inlen); * * Scan the next `inlen' bytes of `inbuf', treating them as subsequent * bytes in a message for which we are computing an sha1 digest. * * This function may be called repeatedly on sequential ``bursts'' * of a total message. */ void sha1_scan (sha1_context_t ctx, const t_uchar *buffer, size_t len) { /* When we already have some bits in our internal buffer concatenate both inputs first. */ if (ctx->buflen != 0) { size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over; mem_cpy (&ctx->buffer[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 64) { sha1_process_blocks (ctx->buffer, ctx->buflen & ~63, ctx); ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ mem_cpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen); } buffer = (const t_uchar *) buffer + add; len -= add; } /* Process available complete blocks. */ if (len >= 64) { sha1_process_blocks (buffer, len & ~63, ctx); buffer = (const t_uchar *) buffer + (len & ~63); len &= 63; } /* Move remaining bytes in internal buffer. */ if (len > 0) { size_t left_over = ctx->buflen; mem_cpy (&ctx->buffer[left_over], buffer, len); left_over += len; if (left_over >= 64) { sha1_process_blocks (ctx->buffer, 64, ctx); left_over -= 64; mem_cpy (ctx->buffer, &ctx->buffer[64], left_over); } ctx->buflen = left_over; } } /*(c sha1_final) * void sha1_final (t_uchar * result, sha1_context_t ctx); * * Declare that a complete message has been scanned using * `state' and `sha1_scan()'. * * Return the 20-byte SHA1 digest in `result', which must point to * storage for at least 20 bytes. * * As a side-effect, `state' is reinitialized and may be used * again with `sha1_scan ()' to process a new message. */ void sha1_final (t_uchar *result, sha1_context_t ctx) { /* Take yet unprocessed bytes into account. */ t_uint32 bytes = ctx->buflen; size_t pad; /* Now count remaining bytes. */ ctx->total[0] += bytes; if (ctx->total[0] < bytes) ++ctx->total[1]; pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; mem_cpy (&ctx->buffer[bytes], fillbuf, pad); /* Put the 64-bit file length in *bits* at the end of the buffer. */ *(t_uint32 *) &ctx->buffer[bytes + pad + 4] = NOTSWAP (ctx->total[0] << 3); *(t_uint32 *) &ctx->buffer[bytes + pad] = NOTSWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); /* Process last bytes. */ sha1_process_blocks (ctx->buffer, bytes + pad + 8, ctx); ((t_uint32 *) result)[0] = NOTSWAP (ctx->current_sha1.A); ((t_uint32 *) result)[1] = NOTSWAP (ctx->current_sha1.B); ((t_uint32 *) result)[2] = NOTSWAP (ctx->current_sha1.C); ((t_uint32 *) result)[3] = NOTSWAP (ctx->current_sha1.D); ((t_uint32 *) result)[4] = NOTSWAP (ctx->current_sha1.E); sha1_context_reset (ctx); } /*(c sha1_alloc_ascii) * t_uchar * sha1_alloc_ascii (alloc_limits limits, t_uchar * result); * * Return a newly allocated 41-byte 0-terminated ascii string * containing a hexadecimal version of the 20-byte binary sha1 sum * pointed to by `result'. */ t_uchar * sha1_alloc_ascii (alloc_limits limits, t_uchar * result) { t_uchar * answer = 0; answer = lim_malloc (limits, 41); if (!answer) return 0; answer[40] = 0; sha1_ascii (answer, result); return answer; } /*(c sha1_ascii) * void sha1_ascii (t_uchar * answer, t_uchar * result); * * Format a 40-byte ascii string containing a hexadecimal version of * the 20-byte binary SHA1 sum pointed to by `result'. * * This function does not add a final 0-byte to the string. */ void sha1_ascii (t_uchar * answer, t_uchar * result) { int x; for (x = 0; x < 20; ++x) { int hi = (0xf & (result[x] >> 4)); int lo = (0xf & result[x]); answer[2 * x] = ((hi >= 10) ? ('a' + (hi - 10)) : ('0' + hi)); answer[2 * x + 1] = ((lo >= 10) ? ('a' + (lo - 10)) : ('0' + lo)); } } /** * \brief Format a 40-byte ascii string containing a hexadecimal version of * the 20-byte binary SHA1 sum pointed to by `sha1'. * * This function does not add a final 0-byte to the string. */ void sha1_to_ascii (t_uchar * answer, sha1_t * sha1) { sha1_ascii (answer, (t_uchar *) sha1); } /** * \brief convert a hex representation of a sha1 to a sha1_t * \param out the sha1 to populate * \return zero on success; */ int sha1_from_ascii (sha1_t * out, t_uchar const * ascii) { unsigned int scanresult; t_uchar const * position = ascii; t_uchar *current = (t_uchar *)out; int count; out->A = 0; out->B = 0; out->C = 0; out->D = 0; out->E = 0; if (str_length (ascii) != 40) return -1; for (count =0; count < 20; ++count) { int ign; if (cvt_hex_to_uint (&ign, &scanresult, position, 2)) return -1; position +=2; current[count] = scanresult; } return 0; } /* --- Code below is the primary difference between md5.c and sha.c --- */ /* SHA1 round constants */ #define K1 0x5a827999L #define K2 0x6ed9eba1L #define K3 0x8f1bbcdcL #define K4 0xca62c1d6L /* Round functions. Note that F2 is the same as F4. */ #define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) #define F2(B,C,D) (B ^ C ^ D) #define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) #define F4(B,C,D) (B ^ C ^ D) /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 64 == 0. Most of this code comes from GnuPG's cipher/sha1.c. */ static void sha1_process_blocks (const void *buffer, size_t len, sha1_context_t ctx) { const t_uint32 *words = buffer; size_t nwords = len / sizeof (t_uint32); const t_uint32 *endp = words + nwords; t_uint32 x[16]; t_uint32 a = ctx->current_sha1.A; t_uint32 b = ctx->current_sha1.B; t_uint32 c = ctx->current_sha1.C; t_uint32 d = ctx->current_sha1.D; t_uint32 e = ctx->current_sha1.E; /* First increment the byte count. RFC 1321 specifies the possible length of the file up to 2^64 bits. Here we only compute the number of bytes. Do a double word increment. */ ctx->total[0] += len; if (ctx->total[0] < len) ++ctx->total[1]; #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) #define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ , (x[I&0x0f] = rol(tm, 1)) ) #define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ + F( B, C, D ) \ + K \ + M; \ B = rol( B, 30 ); \ } while(0) while (words < endp) { t_uint32 tm; int t; /* FIXME: see sha1.c for a better implementation. */ for (t = 0; t < 16; t++) { x[t] = NOTSWAP (*words); words++; } R( a, b, c, d, e, F1, K1, x[ 0] ); R( e, a, b, c, d, F1, K1, x[ 1] ); R( d, e, a, b, c, F1, K1, x[ 2] ); R( c, d, e, a, b, F1, K1, x[ 3] ); R( b, c, d, e, a, F1, K1, x[ 4] ); R( a, b, c, d, e, F1, K1, x[ 5] ); R( e, a, b, c, d, F1, K1, x[ 6] ); R( d, e, a, b, c, F1, K1, x[ 7] ); R( c, d, e, a, b, F1, K1, x[ 8] ); R( b, c, d, e, a, F1, K1, x[ 9] ); R( a, b, c, d, e, F1, K1, x[10] ); R( e, a, b, c, d, F1, K1, x[11] ); R( d, e, a, b, c, F1, K1, x[12] ); R( c, d, e, a, b, F1, K1, x[13] ); R( b, c, d, e, a, F1, K1, x[14] ); R( a, b, c, d, e, F1, K1, x[15] ); R( e, a, b, c, d, F1, K1, M(16) ); R( d, e, a, b, c, F1, K1, M(17) ); R( c, d, e, a, b, F1, K1, M(18) ); R( b, c, d, e, a, F1, K1, M(19) ); R( a, b, c, d, e, F2, K2, M(20) ); R( e, a, b, c, d, F2, K2, M(21) ); R( d, e, a, b, c, F2, K2, M(22) ); R( c, d, e, a, b, F2, K2, M(23) ); R( b, c, d, e, a, F2, K2, M(24) ); R( a, b, c, d, e, F2, K2, M(25) ); R( e, a, b, c, d, F2, K2, M(26) ); R( d, e, a, b, c, F2, K2, M(27) ); R( c, d, e, a, b, F2, K2, M(28) ); R( b, c, d, e, a, F2, K2, M(29) ); R( a, b, c, d, e, F2, K2, M(30) ); R( e, a, b, c, d, F2, K2, M(31) ); R( d, e, a, b, c, F2, K2, M(32) ); R( c, d, e, a, b, F2, K2, M(33) ); R( b, c, d, e, a, F2, K2, M(34) ); R( a, b, c, d, e, F2, K2, M(35) ); R( e, a, b, c, d, F2, K2, M(36) ); R( d, e, a, b, c, F2, K2, M(37) ); R( c, d, e, a, b, F2, K2, M(38) ); R( b, c, d, e, a, F2, K2, M(39) ); R( a, b, c, d, e, F3, K3, M(40) ); R( e, a, b, c, d, F3, K3, M(41) ); R( d, e, a, b, c, F3, K3, M(42) ); R( c, d, e, a, b, F3, K3, M(43) ); R( b, c, d, e, a, F3, K3, M(44) ); R( a, b, c, d, e, F3, K3, M(45) ); R( e, a, b, c, d, F3, K3, M(46) ); R( d, e, a, b, c, F3, K3, M(47) ); R( c, d, e, a, b, F3, K3, M(48) ); R( b, c, d, e, a, F3, K3, M(49) ); R( a, b, c, d, e, F3, K3, M(50) ); R( e, a, b, c, d, F3, K3, M(51) ); R( d, e, a, b, c, F3, K3, M(52) ); R( c, d, e, a, b, F3, K3, M(53) ); R( b, c, d, e, a, F3, K3, M(54) ); R( a, b, c, d, e, F3, K3, M(55) ); R( e, a, b, c, d, F3, K3, M(56) ); R( d, e, a, b, c, F3, K3, M(57) ); R( c, d, e, a, b, F3, K3, M(58) ); R( b, c, d, e, a, F3, K3, M(59) ); R( a, b, c, d, e, F4, K4, M(60) ); R( e, a, b, c, d, F4, K4, M(61) ); R( d, e, a, b, c, F4, K4, M(62) ); R( c, d, e, a, b, F4, K4, M(63) ); R( b, c, d, e, a, F4, K4, M(64) ); R( a, b, c, d, e, F4, K4, M(65) ); R( e, a, b, c, d, F4, K4, M(66) ); R( d, e, a, b, c, F4, K4, M(67) ); R( c, d, e, a, b, F4, K4, M(68) ); R( b, c, d, e, a, F4, K4, M(69) ); R( a, b, c, d, e, F4, K4, M(70) ); R( e, a, b, c, d, F4, K4, M(71) ); R( d, e, a, b, c, F4, K4, M(72) ); R( c, d, e, a, b, F4, K4, M(73) ); R( b, c, d, e, a, F4, K4, M(74) ); R( a, b, c, d, e, F4, K4, M(75) ); R( e, a, b, c, d, F4, K4, M(76) ); R( d, e, a, b, c, F4, K4, M(77) ); R( c, d, e, a, b, F4, K4, M(78) ); R( b, c, d, e, a, F4, K4, M(79) ); a = ctx->current_sha1.A += a; b = ctx->current_sha1.B += b; c = ctx->current_sha1.C += c; d = ctx->current_sha1.D += d; e = ctx->current_sha1.E += e; } } /* tag: Colin Walters Mon, 05 Jan 2004 18:22:29 -0500 (sha1.c) */