aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-05-16 02:38:26 +0000
committerRob Landley <rob@landley.net>2006-05-16 02:38:26 +0000
commit34b5319d86eb639794dcccc56a443e7a35daf5d3 (patch)
treee8a8ee0a912d46c699fab3b5fba67c33fcced333
parentd272dc7cb306995c6a8ec78c13a4aa1021d33a53 (diff)
downloadbusybox-w32-34b5319d86eb639794dcccc56a443e7a35daf5d3.tar.gz
busybox-w32-34b5319d86eb639794dcccc56a443e7a35daf5d3.tar.bz2
busybox-w32-34b5319d86eb639794dcccc56a443e7a35daf5d3.zip
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.
-rw-r--r--coreutils/md5_sha1_sum.c2
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/md5.c129
3 files changed, 44 insertions, 89 deletions
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index 633b6e534..eeee18449 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)
71 bb_error_msg_and_die("algorithm not supported"); 71 bb_error_msg_and_die("algorithm not supported");
72 } 72 }
73 73
74 while (0 < (count = read(src_fd, in_buf, sizeof in_buf))) { 74 while (0 < (count = read(src_fd, in_buf, 4096))) {
75 update(in_buf, count, &context); 75 update(in_buf, count, &context);
76 } 76 }
77 77
diff --git a/include/libbb.h b/include/libbb.h
index 39361a232..02927cd77 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -506,7 +506,7 @@ typedef struct _md5_ctx_t_ {
506 uint32_t B; 506 uint32_t B;
507 uint32_t C; 507 uint32_t C;
508 uint32_t D; 508 uint32_t D;
509 uint32_t total[2]; 509 uint64_t total;
510 uint32_t buflen; 510 uint32_t buflen;
511 char buffer[128]; 511 char buffer[128];
512} md5_ctx_t; 512} md5_ctx_t;
diff --git a/libbb/md5.c b/libbb/md5.c
index b5aa89fc6..584f5fe6f 100644
--- a/libbb/md5.c
+++ b/libbb/md5.c
@@ -33,15 +33,9 @@
33# elif defined(bswap_32) 33# elif defined(bswap_32)
34# define SWAP(n) bswap_32(n) 34# define SWAP(n) bswap_32(n)
35# else 35# else
36# define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24)) 36# define SWAP(n) ((n << 24) | ((n&0xFF00)<<8) | ((n&0xFF0000)>>8) | (n>>24))
37# endif 37# endif
38 38
39# if MD5_SIZE_VS_SPEED == 0
40/* This array contains the bytes used to pad the buffer to the next
41 64-byte boundary. (RFC 1321, 3.1: Step 1) */
42static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
43# endif /* MD5_SIZE_VS_SPEED == 0 */
44
45/* Initialize structure containing state of computation. 39/* Initialize structure containing state of computation.
46 * (RFC 1321, 3.3: Step 3) 40 * (RFC 1321, 3.3: Step 3)
47 */ 41 */
@@ -52,7 +46,7 @@ void md5_begin(md5_ctx_t *ctx)
52 ctx->C = 0x98badcfe; 46 ctx->C = 0x98badcfe;
53 ctx->D = 0x10325476; 47 ctx->D = 0x10325476;
54 48
55 ctx->total[0] = ctx->total[1] = 0; 49 ctx->total = 0;
56 ctx->buflen = 0; 50 ctx->buflen = 0;
57} 51}
58 52
@@ -66,17 +60,11 @@ void md5_begin(md5_ctx_t *ctx)
66# define FH(b, c, d) (b ^ c ^ d) 60# define FH(b, c, d) (b ^ c ^ d)
67# define FI(b, c, d) (c ^ (b | ~d)) 61# define FI(b, c, d) (c ^ (b | ~d))
68 62
69/* Starting with the result of former calls of this function (or the 63/* Hash a single block, 64 bytes long and 4-byte aligned. */
70 * initialization function update the context for the next LEN bytes 64static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
71 * starting at BUFFER.
72 * It is necessary that LEN is a multiple of 64!!!
73 */
74static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx)
75{ 65{
76 uint32_t correct_words[16]; 66 uint32_t correct_words[16];
77 const uint32_t *words = buffer; 67 const uint32_t *words = buffer;
78 size_t nwords = len / sizeof(uint32_t);
79 const uint32_t *endp = words + nwords;
80 68
81# if MD5_SIZE_VS_SPEED > 0 69# if MD5_SIZE_VS_SPEED > 0
82 static const uint32_t C_array[] = { 70 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)
126 uint32_t C = ctx->C; 114 uint32_t C = ctx->C;
127 uint32_t D = ctx->D; 115 uint32_t D = ctx->D;
128 116
129 /* First increment the byte count. RFC 1321 specifies the possible
130 length of the file up to 2^64 bits. Here we only compute the
131 number of bytes. Do a double word increment. */
132 ctx->total[0] += len;
133 if (ctx->total[0] < len)
134 ++ctx->total[1];
135
136 /* Process all bytes in the buffer with 64 bytes in each round of 117 /* Process all bytes in the buffer with 64 bytes in each round of
137 the loop. */ 118 the loop. */
138 while (words < endp) {
139 uint32_t *cwp = correct_words; 119 uint32_t *cwp = correct_words;
140 uint32_t A_save = A; 120 uint32_t A_save = A;
141 uint32_t B_save = B; 121 uint32_t B_save = B;
@@ -397,7 +377,6 @@ static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx)
397 B += B_save; 377 B += B_save;
398 C += C_save; 378 C += C_save;
399 D += D_save; 379 D += D_save;
400 }
401 380
402 /* Put checksum in context given as argument. */ 381 /* Put checksum in context given as argument. */
403 ctx->A = A; 382 ctx->A = A;
@@ -406,55 +385,39 @@ static void md5_hash_block(const void *buffer, size_t len, md5_ctx_t *ctx)
406 ctx->D = D; 385 ctx->D = D;
407} 386}
408 387
409/* Starting with the result of former calls of this function (or the 388/* Feed data through a temporary buffer to call md5_hash_aligned_block()
410 * initialization function update the context for the next LEN bytes 389 * with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
411 * starting at BUFFER. 390 * This function's internal buffer remembers previous data until it has 64
412 * It is NOT required that LEN is a multiple of 64. 391 * bytes worth to pass on. Call md5_end() to flush this buffer. */
413 */
414 392
415static void md5_hash_bytes(const void *buffer, size_t len, md5_ctx_t *ctx) 393void md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
416{ 394{
417 /* When we already have some bits in our internal buffer concatenate 395 char *buf=(char *)buffer;
418 both inputs first. */
419 if (ctx->buflen != 0) {
420 size_t left_over = ctx->buflen;
421 size_t add = 128 - left_over > len ? len : 128 - left_over;
422
423 memcpy(&ctx->buffer[left_over], buffer, add);
424 ctx->buflen += add;
425
426 if (left_over + add > 64) {
427 md5_hash_block(ctx->buffer, (left_over + add) & ~63, ctx);
428 /* The regions in the following copy operation cannot overlap. */
429 memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
430 (left_over + add) & 63);
431 ctx->buflen = (left_over + add) & 63;
432 }
433 396
434 buffer = (const char *) buffer + add; 397 /* RFC 1321 specifies the possible length of the file up to 2^64 bits,
435 len -= add; 398 * Here we only track the number of bytes. */
436 }
437 399
438 /* Process available complete blocks. */ 400 ctx->total += len;
439 if (len > 64) {
440 md5_hash_block(buffer, len & ~63, ctx);
441 buffer = (const char *) buffer + (len & ~63);
442 len &= 63;
443 }
444 401
445 /* Move remaining bytes in internal buffer. */ 402 // Process all input.
446 if (len > 0) {
447 memcpy(ctx->buffer, buffer, len);
448 ctx->buflen = len;
449 }
450}
451 403
452void md5_hash(const void *data, size_t length, md5_ctx_t *ctx) 404 while (len) {
453{ 405 int i = 64 - ctx->buflen;
454 if (length % 64 == 0) { 406
455 md5_hash_block(data, length, ctx); 407 // Copy data into aligned buffer.
456 } else { 408
457 md5_hash_bytes(data, length, ctx); 409 if (i > len) i = len;
410 memcpy(ctx->buffer + ctx->buflen, buf, i);
411 len -= i;
412 ctx->buflen += i;
413 buf += i;
414
415 // When buffer fills up, process it.
416
417 if (ctx->buflen == 64) {
418 md5_hash_block(ctx->buffer, ctx);
419 ctx->buflen = 0;
420 }
458 } 421 }
459} 422}
460 423
@@ -468,31 +431,23 @@ void md5_hash(const void *data, size_t length, md5_ctx_t *ctx)
468 */ 431 */
469void *md5_end(void *resbuf, md5_ctx_t *ctx) 432void *md5_end(void *resbuf, md5_ctx_t *ctx)
470{ 433{
471 /* Take yet unprocessed bytes into account. */ 434 char *buf = ctx->buffer;
472 uint32_t bytes = ctx->buflen; 435 int i;
473 size_t pad;
474 436
475 /* Now count remaining bytes. */ 437 /* Pad data to block size. */
476 ctx->total[0] += bytes;
477 if (ctx->total[0] < bytes)
478 ++ctx->total[1];
479 438
480 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; 439 buf[ctx->buflen++] = 0x80;
481# if MD5_SIZE_VS_SPEED > 0 440 memset(buf + ctx->buflen, 0, 128 - ctx->buflen);
482 memset(&ctx->buffer[bytes], 0, pad);
483 ctx->buffer[bytes] = 0x80;
484# else
485 memcpy(&ctx->buffer[bytes], fillbuf, pad);
486# endif /* MD5_SIZE_VS_SPEED > 0 */
487 441
488 /* Put the 64-bit file length in *bits* at the end of the buffer. */ 442 /* Put the 64-bit file length in *bits* at the end of the buffer. */
489 *(uint32_t *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3); 443 ctx->total <<= 3;
490 *(uint32_t *) & ctx->buffer[bytes + pad + 4] = 444 if (ctx->buflen > 56) buf += 64;
491 SWAP(((ctx->total[1] << 3) | (ctx->total[0] >> 29))); 445 for (i = 0; i < 8; i++) buf[56 + i] = ctx->total >> (i*8);
492 446
493 /* Process last bytes. */ 447 /* Process last bytes. */
494 md5_hash_block(ctx->buffer, bytes + pad + 8, ctx); 448 if (buf != ctx->buffer) md5_hash_block(ctx->buffer, ctx);
495 449 md5_hash_block(buf, ctx);
450
496 /* Put result from CTX in first 16 bytes following RESBUF. The result is 451 /* Put result from CTX in first 16 bytes following RESBUF. The result is
497 * always in little endian byte order, so that a byte-wise output yields 452 * always in little endian byte order, so that a byte-wise output yields
498 * to the wanted ASCII representation of the message digest. 453 * to the wanted ASCII representation of the message digest.