From 34b5319d86eb639794dcccc56a443e7a35daf5d3 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 16 May 2006 02:38:26 +0000 Subject: Make md5 calculation always go through an the buffer so that A) we don't handle packets out of sequence if some data goes through the buffer and some doesn't, B) it works on systems that can't handle aligned access, C) we just have one code path to worry about. While we're at it, sizeof() and RESERVE_CONFIG_BUFFER() really don't combine well, which is why md5sum has been reading and processing data 4 bytes at a time. I suspect that the existence of CONFIG_MD5_SIZE_VS_SPEED to do loop unrolling and such in the algorithm was an attempt to work around that bug. --- coreutils/md5_sha1_sum.c | 2 +- include/libbb.h | 2 +- libbb/md5.c | 129 +++++++++++++++-------------------------------- 3 files changed, 44 insertions(+), 89 deletions(-) diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index 633b6e5..eeee184 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c @@ -71,7 +71,7 @@ static uint8_t *hash_file(const char *filename, hash_algo_t hash_algo) bb_error_msg_and_die("algorithm not supported"); } - while (0 < (count = read(src_fd, in_buf, sizeof in_buf))) { + while (0 < (count = read(src_fd, in_buf, 4096))) { update(in_buf, count, &context); } diff --git a/include/libbb.h b/include/libbb.h index 39361a2..02927cd 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -506,7 +506,7 @@ typedef struct _md5_ctx_t_ { uint32_t B; uint32_t C; uint32_t D; - uint32_t total[2]; + uint64_t total; uint32_t buflen; char buffer[128]; } md5_ctx_t; diff --git a/libbb/md5.c b/libbb/md5.c index b5aa89f..584f5fe 100644 --- a/libbb/md5.c +++ b/libbb/md5.c @@ -33,15 +33,9 @@ # elif defined(bswap_32) # define SWAP(n) bswap_32(n) # else -# define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24)) +# define SWAP(n) ((n << 24) | ((n&0xFF00)<<8) | ((n&0xFF0000)>>8) | (n>>24)) # endif -# if MD5_SIZE_VS_SPEED == 0 -/* 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, ... */ }; -# endif /* MD5_SIZE_VS_SPEED == 0 */ - /* Initialize structure containing state of computation. * (RFC 1321, 3.3: Step 3) */ @@ -52,7 +46,7 @@ void md5_begin(md5_ctx_t *ctx) ctx->C = 0x98badcfe; ctx->D = 0x10325476; - ctx->total[0] = ctx->total[1] = 0; + ctx->total = 0; ctx->buflen = 0; } @@ -66,17 +60,11 @@ void md5_begin(md5_ctx_t *ctx) # define FH(b, c, d) (b ^ c ^ d) # define FI(b, c, d) (c ^ (b | ~d)) -/* Starting with the result of former calls of this function (or the - * initialization function update the context for the next LEN bytes - * starting at BUFFER. - * It is necessary that LEN is a multiple of 64!!! - */ -static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx) +/* Hash a single block, 64 bytes long and 4-byte aligned. */ +static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) { uint32_t correct_words[16]; const uint32_t *words = buffer; - size_t nwords = len / sizeof(uint32_t); - const uint32_t *endp = words + nwords; # if MD5_SIZE_VS_SPEED > 0 static const uint32_t C_array[] = { @@ -126,16 +114,8 @@ static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx) uint32_t C = ctx->C; uint32_t D = ctx->D; - /* 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]; - /* Process all bytes in the buffer with 64 bytes in each round of the loop. */ - while (words < endp) { uint32_t *cwp = correct_words; uint32_t A_save = A; uint32_t B_save = B; @@ -397,7 +377,6 @@ static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx) B += B_save; C += C_save; D += D_save; - } /* Put checksum in context given as argument. */ ctx->A = A; @@ -406,55 +385,39 @@ static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx) ctx->D = D; } -/* Starting with the result of former calls of this function (or the - * initialization function update the context for the next LEN bytes - * starting at BUFFER. - * It is NOT required that LEN is a multiple of 64. - */ +/* Feed data through a temporary buffer to call md5_hash_aligned_block() + * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. + * This function's internal buffer remembers previous data until it has 64 + * bytes worth to pass on. Call md5_end() to flush this buffer. */ -static void md5_hash_bytes(const void *buffer, size_t len, md5_ctx_t *ctx) +void md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) { - /* 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; - - memcpy(&ctx->buffer[left_over], buffer, add); - ctx->buflen += add; - - if (left_over + add > 64) { - md5_hash_block(ctx->buffer, (left_over + add) & ~63, ctx); - /* 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; - } + char *buf=(char *)buffer; - buffer = (const char *) buffer + add; - len -= add; - } + /* RFC 1321 specifies the possible length of the file up to 2^64 bits, + * Here we only track the number of bytes. */ - /* Process available complete blocks. */ - if (len > 64) { - md5_hash_block(buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } + ctx->total += len; - /* Move remaining bytes in internal buffer. */ - if (len > 0) { - memcpy(ctx->buffer, buffer, len); - ctx->buflen = len; - } -} + // Process all input. -void md5_hash(const void *data, size_t length, md5_ctx_t *ctx) -{ - if (length % 64 == 0) { - md5_hash_block(data, length, ctx); - } else { - md5_hash_bytes(data, length, ctx); + while (len) { + int i = 64 - ctx->buflen; + + // Copy data into aligned buffer. + + if (i > len) i = len; + memcpy(ctx->buffer + ctx->buflen, buf, i); + len -= i; + ctx->buflen += i; + buf += i; + + // When buffer fills up, process it. + + if (ctx->buflen == 64) { + md5_hash_block(ctx->buffer, ctx); + ctx->buflen = 0; + } } } @@ -468,31 +431,23 @@ void md5_hash(const void *data, size_t length, md5_ctx_t *ctx) */ void *md5_end(void *resbuf, md5_ctx_t *ctx) { - /* Take yet unprocessed bytes into account. */ - uint32_t bytes = ctx->buflen; - size_t pad; + char *buf = ctx->buffer; + int i; - /* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; + /* Pad data to block size. */ - pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; -# if MD5_SIZE_VS_SPEED > 0 - memset(&ctx->buffer[bytes], 0, pad); - ctx->buffer[bytes] = 0x80; -# else - memcpy(&ctx->buffer[bytes], fillbuf, pad); -# endif /* MD5_SIZE_VS_SPEED > 0 */ + buf[ctx->buflen++] = 0x80; + memset(buf + ctx->buflen, 0, 128 - ctx->buflen); /* Put the 64-bit file length in *bits* at the end of the buffer. */ - *(uint32_t *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3); - *(uint32_t *) & ctx->buffer[bytes + pad + 4] = - SWAP(((ctx->total[1] << 3) | (ctx->total[0] >> 29))); + ctx->total <<= 3; + if (ctx->buflen > 56) buf += 64; + for (i = 0; i < 8; i++) buf[56 + i] = ctx->total >> (i*8); /* Process last bytes. */ - md5_hash_block(ctx->buffer, bytes + pad + 8, ctx); - + if (buf != ctx->buffer) md5_hash_block(ctx->buffer, ctx); + md5_hash_block(buf, ctx); + /* Put result from CTX in first 16 bytes following RESBUF. The result is * always in little endian byte order, so that a byte-wise output yields * to the wanted ASCII representation of the message digest. -- cgit v1.1