X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=inline;f=lib%2Fsha.c;h=b645bf4026221841e756803853456a8c956307bb;hb=f81666cf0bfd795a33feea079c6196ed7fc39f2b;hp=6f4c5c2c512764e1c7cd6135974be3221afee889;hpb=d5d02232ba5ddc267987a732e037a264120f7ef7;p=gnulib.git diff --git a/lib/sha.c b/lib/sha.c index 6f4c5c2c5..b645bf402 100644 --- a/lib/sha.c +++ b/lib/sha.c @@ -1,7 +1,7 @@ /* 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 Scott G. Miller + Copyright (C) 2000, 2001, 2003 Scott G. Miller Credits: Robert Klep -- Expansion function fix @@ -11,19 +11,14 @@ # include #endif +#include "sha.h" + #include -#if STDC_HEADERS || defined _LIBC -# include -# include -#else -# ifndef HAVE_MEMCPY -# define memcpy(d, s, n) bcopy ((s), (d), (n)) -# endif -#endif +#include +#include -#include "md5.h" -#include "sha.h" +#include "unlocked-io.h" /* Not-swap is a macro that does an endian swap on architectures that are @@ -40,6 +35,13 @@ # define SWAP(n) (n) #endif +#define BLOCKSIZE 4096 +/* Ensure that BLOCKSIZE is a multiple of 64. */ +#if BLOCKSIZE % 64 != 0 +/* FIXME-someday (soon?): use #error instead of this kludge. */ +"invalid BLOCKSIZE" +#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 unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; @@ -117,8 +119,6 @@ sha_finish_ctx (struct sha_ctx *ctx, void *resbuf) int sha_stream (FILE *stream, void *resblock) { - /* Important: BLOCKSIZE must be a multiple of 64. */ -#define BLOCKSIZE 4096 struct sha_ctx ctx; char buffer[BLOCKSIZE + 72]; size_t sum; @@ -136,19 +136,31 @@ sha_stream (FILE *stream, void *resblock) sum = 0; /* Read block. Take care for partial reads. */ - do + while (1) { n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); sum += n; - } - while (sum < BLOCKSIZE && n != 0); - if (n == 0 && ferror (stream)) - return 1; - /* If end of file is reached, end the loop. */ - if (n == 0) - break; + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % 64 == 0 @@ -156,7 +168,9 @@ sha_stream (FILE *stream, void *resblock) sha_process_block (buffer, BLOCKSIZE, &ctx); } - /* Add the last bytes if necessary. */ + process_partial_block:; + + /* Process any remaining bytes. */ if (sum > 0) sha_process_bytes (buffer, sum, &ctx); @@ -197,13 +211,14 @@ sha_process_bytes (const void *buffer, size_t len, struct sha_ctx *ctx) memcpy (&ctx->buffer[left_over], buffer, add); ctx->buflen += add; - if (left_over + add > 64) + if (ctx->buflen > 64) { - sha_process_block (ctx->buffer, (left_over + add) & ~63, ctx); + sha_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], - (left_over + add) & 63); - ctx->buflen = (left_over + add) & 63; + ctx->buflen); } buffer = (const char *) buffer + add; @@ -211,18 +226,46 @@ sha_process_bytes (const void *buffer, size_t len, struct sha_ctx *ctx) } /* Process available complete blocks. */ - if (len > 64) + if (len >= 64) { - sha_process_block (buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; +#if !_STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) +# else +# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } } /* Move remaining bytes in internal buffer. */ if (len > 0) { - memcpy (ctx->buffer, buffer, len); - ctx->buflen = len; + size_t left_over = ctx->buflen; + + memcpy (&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; } } @@ -234,24 +277,15 @@ sha_process_bytes (const void *buffer, size_t len, struct sha_ctx *ctx) #define K3 0x8f1bbcdcL #define K4 0xca62c1d6L -/* Round functions. Note that F2() is used in both rounds 2 and 4 */ +/* 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 ) ) ) - -#if SHA_DEBUG -char bin2hex[16]={'0','1','2','3','4','5','6','7', - '8','9','a','b','c','d','e','f'}; -# define BH(x) bin2hex[x] -# define PH(x) \ - printf("%c%c%c%c%c%c%c%c\t", BH((x>>28)&0xf), \ - BH((x>>24)&0xf), BH((x>>20)&0xf), BH((x>>16)&0xf),\ - BH((x>>12)&0xf), BH((x>>8)&0xf), BH((x>>4)&0xf),\ - BH(x&0xf)); -#endif +#define F4(B,C,D) (B ^ C ^ D) /* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. */ + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ void sha_process_block (const void *buffer, size_t len, struct sha_ctx *ctx) @@ -259,12 +293,12 @@ sha_process_block (const void *buffer, size_t len, struct sha_ctx *ctx) const md5_uint32 *words = buffer; size_t nwords = len / sizeof (md5_uint32); const md5_uint32 *endp = words + nwords; - md5_uint32 W[80]; - md5_uint32 A = ctx->A; - md5_uint32 B = ctx->B; - md5_uint32 C = ctx->C; - md5_uint32 D = ctx->D; - md5_uint32 E = ctx->E; + md5_uint32 x[16]; + md5_uint32 a = ctx->A; + md5_uint32 b = ctx->B; + md5_uint32 c = ctx->C; + md5_uint32 d = ctx->D; + md5_uint32 e = ctx->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 @@ -273,65 +307,113 @@ sha_process_block (const void *buffer, size_t len, struct sha_ctx *ctx) if (ctx->total[0] < len) ++ctx->total[1]; +#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) { + md5_uint32 tm; int t; + /* FIXME: see sha1.c for a better implementation. */ for (t = 0; t < 16; t++) { - W[t] = NOTSWAP (*words); + x[t] = NOTSWAP (*words); words++; } - /* SHA1 Data expansion */ - for (t = 16; t < 80; t++) - { - md5_uint32 x = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; - W[t] = rol (x, 1); - } - - /* SHA1 main loop (t=0 to 79) - This is broken down into four subloops in order to use - the correct round function and constant */ - for (t = 0; t < 20; t++) - { - md5_uint32 tmp = rol (A, 5) + F1 (B, C, D) + E + W[t] + K1; - E = D; - D = C; - C = rol (B, 30); - B = A; - A = tmp; - } - for (; t < 40; t++) - { - md5_uint32 tmp = rol (A, 5) + F2 (B, C, D) + E + W[t] + K2; - E = D; - D = C; - C = rol (B, 30); - B = A; - A = tmp; - } - for (; t < 60; t++) - { - md5_uint32 tmp = rol (A, 5) + F3 (B, C, D) + E + W[t] + K3; - E = D; - D = C; - C = rol (B, 30); - B = A; - A = tmp; - } - for (; t < 80; t++) - { - md5_uint32 tmp = rol (A, 5) + F2 (B, C, D) + E + W[t] + K4; - E = D; - D = C; - C = rol (B, 30); - B = A; - A = tmp; - } - A = ctx->A += A; - B = ctx->B += B; - C = ctx->C += C; - D = ctx->D += D; - E = ctx->E += E; + 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->A += a; + b = ctx->B += b; + c = ctx->C += c; + d = ctx->D += d; + e = ctx->E += e; } }