aboutsummaryrefslogtreecommitdiff
path: root/libbb/md5.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/md5.c')
-rw-r--r--libbb/md5.c245
1 files changed, 130 insertions, 115 deletions
diff --git a/libbb/md5.c b/libbb/md5.c
index d8655ba91..051c8ede4 100644
--- a/libbb/md5.c
+++ b/libbb/md5.c
@@ -1,7 +1,7 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * md5.c - Compute MD5 checksum of strings according to the 3 * Compute MD5 checksum of strings according to the
4 * definition of MD5 in RFC 1321 from April 1992. 4 * definition of MD5 in RFC 1321 from April 1992.
5 * 5 *
6 * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. 6 * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
7 * 7 *
@@ -33,8 +33,7 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx)
33 ctx->B = 0xefcdab89; 33 ctx->B = 0xefcdab89;
34 ctx->C = 0x98badcfe; 34 ctx->C = 0x98badcfe;
35 ctx->D = 0x10325476; 35 ctx->D = 0x10325476;
36 ctx->total = 0; 36 ctx->total64 = 0;
37 ctx->buflen = 0;
38} 37}
39 38
40/* These are the four functions used in the four steps of the MD5 algorithm 39/* These are the four functions used in the four steps of the MD5 algorithm
@@ -49,13 +48,14 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx)
49 48
50#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s)))) 49#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s))))
51 50
52/* Hash a single block, 64 bytes long and 4-byte aligned. */ 51/* Hash a single block, 64 bytes long and 4-byte aligned */
53static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) 52static void md5_process_block64(md5_ctx_t *ctx)
54{ 53{
55 uint32_t correct_words[16];
56 const uint32_t *words = buffer;
57
58#if MD5_SIZE_VS_SPEED > 0 54#if MD5_SIZE_VS_SPEED > 0
55 /* Before we start, one word to the strange constants.
56 They are defined in RFC 1321 as
57 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
58 */
59 static const uint32_t C_array[] = { 59 static const uint32_t C_array[] = {
60 /* round 1 */ 60 /* round 1 */
61 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 61 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
@@ -64,7 +64,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
64 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 64 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
65 /* round 2 */ 65 /* round 2 */
66 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 66 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
67 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 67 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
68 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 68 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
69 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 69 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
70 /* round 3 */ 70 /* round 3 */
@@ -86,40 +86,33 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
86 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ 86 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
87 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ 87 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
88 }; 88 };
89# if MD5_SIZE_VS_SPEED > 1
90 static const char S_array[] ALIGN1 = {
91 7, 12, 17, 22,
92 5, 9, 14, 20,
93 4, 11, 16, 23,
94 6, 10, 15, 21
95 };
96# endif /* MD5_SIZE_VS_SPEED > 1 */
97#endif 89#endif
90 uint32_t *words = (void*) ctx->wbuffer;
98 uint32_t A = ctx->A; 91 uint32_t A = ctx->A;
99 uint32_t B = ctx->B; 92 uint32_t B = ctx->B;
100 uint32_t C = ctx->C; 93 uint32_t C = ctx->C;
101 uint32_t D = ctx->D; 94 uint32_t D = ctx->D;
102 95
103 /* Process all bytes in the buffer with 64 bytes in each round of 96#if MD5_SIZE_VS_SPEED >= 2 /* 2 or 3 */
104 the loop. */
105 uint32_t *cwp = correct_words;
106 uint32_t A_save = A;
107 uint32_t B_save = B;
108 uint32_t C_save = C;
109 uint32_t D_save = D;
110 97
111#if MD5_SIZE_VS_SPEED > 1 98 static const char S_array[] ALIGN1 = {
99 7, 12, 17, 22,
100 5, 9, 14, 20,
101 4, 11, 16, 23,
102 6, 10, 15, 21
103 };
112 const uint32_t *pc; 104 const uint32_t *pc;
113 const char *pp; 105 const char *pp;
114 const char *ps; 106 const char *ps;
115 int i; 107 int i;
116 uint32_t temp; 108 uint32_t temp;
117 109
110# if BB_BIG_ENDIAN
118 for (i = 0; i < 16; i++) 111 for (i = 0; i < 16; i++)
119 cwp[i] = SWAP_LE32(words[i]); 112 words[i] = SWAP_LE32(words[i]);
120 words += 16; 113# endif
121 114
122# if MD5_SIZE_VS_SPEED > 2 115# if MD5_SIZE_VS_SPEED == 3
123 pc = C_array; 116 pc = C_array;
124 pp = P_array; 117 pp = P_array;
125 ps = S_array - 4; 118 ps = S_array - 4;
@@ -141,7 +134,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
141 case 3: 134 case 3:
142 temp += FI(B, C, D); 135 temp += FI(B, C, D);
143 } 136 }
144 temp += cwp[(int) (*pp++)] + *pc++; 137 temp += words[(int) (*pp++)] + *pc++;
145 temp = rotl32(temp, ps[i & 3]); 138 temp = rotl32(temp, ps[i & 3]);
146 temp += B; 139 temp += B;
147 A = D; 140 A = D;
@@ -149,13 +142,13 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
149 C = B; 142 C = B;
150 B = temp; 143 B = temp;
151 } 144 }
152# else 145# else /* MD5_SIZE_VS_SPEED == 2 */
153 pc = C_array; 146 pc = C_array;
154 pp = P_array; 147 pp = P_array;
155 ps = S_array; 148 ps = S_array;
156 149
157 for (i = 0; i < 16; i++) { 150 for (i = 0; i < 16; i++) {
158 temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++; 151 temp = A + FF(B, C, D) + words[(int) (*pp++)] + *pc++;
159 temp = rotl32(temp, ps[i & 3]); 152 temp = rotl32(temp, ps[i & 3]);
160 temp += B; 153 temp += B;
161 A = D; 154 A = D;
@@ -165,7 +158,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
165 } 158 }
166 ps += 4; 159 ps += 4;
167 for (i = 0; i < 16; i++) { 160 for (i = 0; i < 16; i++) {
168 temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++; 161 temp = A + FG(B, C, D) + words[(int) (*pp++)] + *pc++;
169 temp = rotl32(temp, ps[i & 3]); 162 temp = rotl32(temp, ps[i & 3]);
170 temp += B; 163 temp += B;
171 A = D; 164 A = D;
@@ -175,7 +168,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
175 } 168 }
176 ps += 4; 169 ps += 4;
177 for (i = 0; i < 16; i++) { 170 for (i = 0; i < 16; i++) {
178 temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++; 171 temp = A + FH(B, C, D) + words[(int) (*pp++)] + *pc++;
179 temp = rotl32(temp, ps[i & 3]); 172 temp = rotl32(temp, ps[i & 3]);
180 temp += B; 173 temp += B;
181 A = D; 174 A = D;
@@ -185,7 +178,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
185 } 178 }
186 ps += 4; 179 ps += 4;
187 for (i = 0; i < 16; i++) { 180 for (i = 0; i < 16; i++) {
188 temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++; 181 temp = A + FI(B, C, D) + words[(int) (*pp++)] + *pc++;
189 temp = rotl32(temp, ps[i & 3]); 182 temp = rotl32(temp, ps[i & 3]);
190 temp += B; 183 temp += B;
191 A = D; 184 A = D;
@@ -193,35 +186,41 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
193 C = B; 186 C = B;
194 B = temp; 187 B = temp;
195 } 188 }
189# endif
190 /* Add checksum to the starting values */
191 ctx->A += A;
192 ctx->B += B;
193 ctx->C += C;
194 ctx->D += D;
195
196#else /* MD5_SIZE_VS_SPEED == 0 or 1 */
197
198 uint32_t A_save = A;
199 uint32_t B_save = B;
200 uint32_t C_save = C;
201 uint32_t D_save = D;
202# if MD5_SIZE_VS_SPEED == 1
203 const uint32_t *pc;
204 const char *pp;
205 int i;
206# endif
196 207
197# endif /* MD5_SIZE_VS_SPEED > 2 */
198#else
199 /* First round: using the given function, the context and a constant 208 /* First round: using the given function, the context and a constant
200 the next context is computed. Because the algorithms processing 209 the next context is computed. Because the algorithm's processing
201 unit is a 32-bit word and it is determined to work on words in 210 unit is a 32-bit word and it is determined to work on words in
202 little endian byte order we perhaps have to change the byte order 211 little endian byte order we perhaps have to change the byte order
203 before the computation. To reduce the work for the next steps 212 before the computation. To reduce the work for the next steps
204 we store the swapped words in the array CORRECT_WORDS. */ 213 we save swapped words in WORDS array. */
214# undef OP
205# define OP(a, b, c, d, s, T) \ 215# define OP(a, b, c, d, s, T) \
206 do { \ 216 do { \
207 a += FF(b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \ 217 a += FF(b, c, d) + (*words IF_BIG_ENDIAN(= SWAP_LE32(*words))) + T; \
208 ++words; \ 218 words++; \
209 a = rotl32(a, s); \ 219 a = rotl32(a, s); \
210 a += b; \ 220 a += b; \
211 } while (0) 221 } while (0)
212 222
213 /* Before we start, one word to the strange constants. 223 /* Round 1 */
214 They are defined in RFC 1321 as
215 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
216 */
217
218# if MD5_SIZE_VS_SPEED == 1
219 const uint32_t *pc;
220 const char *pp;
221 int i;
222# endif /* MD5_SIZE_VS_SPEED */
223
224 /* Round 1. */
225# if MD5_SIZE_VS_SPEED == 1 224# if MD5_SIZE_VS_SPEED == 1
226 pc = C_array; 225 pc = C_array;
227 for (i = 0; i < 4; i++) { 226 for (i = 0; i < 4; i++) {
@@ -247,20 +246,21 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
247 OP(D, A, B, C, 12, 0xfd987193); 246 OP(D, A, B, C, 12, 0xfd987193);
248 OP(C, D, A, B, 17, 0xa679438e); 247 OP(C, D, A, B, 17, 0xa679438e);
249 OP(B, C, D, A, 22, 0x49b40821); 248 OP(B, C, D, A, 22, 0x49b40821);
250# endif /* MD5_SIZE_VS_SPEED == 1 */ 249# endif
250 words -= 16;
251 251
252 /* For the second to fourth round we have the possibly swapped words 252 /* For the second to fourth round we have the possibly swapped words
253 in CORRECT_WORDS. Redefine the macro to take an additional first 253 in WORDS. Redefine the macro to take an additional first
254 argument specifying the function to use. */ 254 argument specifying the function to use. */
255# undef OP 255# undef OP
256# define OP(f, a, b, c, d, k, s, T) \ 256# define OP(f, a, b, c, d, k, s, T) \
257 do { \ 257 do { \
258 a += f(b, c, d) + correct_words[k] + T; \ 258 a += f(b, c, d) + words[k] + T; \
259 a = rotl32(a, s); \ 259 a = rotl32(a, s); \
260 a += b; \ 260 a += b; \
261 } while (0) 261 } while (0)
262 262
263 /* Round 2. */ 263 /* Round 2 */
264# if MD5_SIZE_VS_SPEED == 1 264# if MD5_SIZE_VS_SPEED == 1
265 pp = P_array; 265 pp = P_array;
266 for (i = 0; i < 4; i++) { 266 for (i = 0; i < 4; i++) {
@@ -286,9 +286,9 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
286 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); 286 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
287 OP(FG, C, D, A, B, 7, 14, 0x676f02d9); 287 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
288 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); 288 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
289# endif /* MD5_SIZE_VS_SPEED == 1 */ 289# endif
290 290
291 /* Round 3. */ 291 /* Round 3 */
292# if MD5_SIZE_VS_SPEED == 1 292# if MD5_SIZE_VS_SPEED == 1
293 for (i = 0; i < 4; i++) { 293 for (i = 0; i < 4; i++) {
294 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); 294 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
@@ -313,9 +313,9 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
313 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); 313 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
314 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); 314 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
315 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); 315 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
316# endif /* MD5_SIZE_VS_SPEED == 1 */ 316# endif
317 317
318 /* Round 4. */ 318 /* Round 4 */
319# if MD5_SIZE_VS_SPEED == 1 319# if MD5_SIZE_VS_SPEED == 1
320 for (i = 0; i < 4; i++) { 320 for (i = 0; i < 4; i++) {
321 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); 321 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
@@ -340,52 +340,62 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
340 OP(FI, D, A, B, C, 11, 10, 0xbd3af235); 340 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
341 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); 341 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
342 OP(FI, B, C, D, A, 9, 21, 0xeb86d391); 342 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
343# endif /* MD5_SIZE_VS_SPEED == 1 */ 343# endif
344#endif /* MD5_SIZE_VS_SPEED > 1 */ 344 /* Add checksum to the starting values */
345 345 ctx->A = A_save + A;
346 /* Add the starting values of the context. */ 346 ctx->B = B_save + B;
347 A += A_save; 347 ctx->C = C_save + C;
348 B += B_save; 348 ctx->D = D_save + D;
349 C += C_save; 349#endif
350 D += D_save;
351
352 /* Put checksum in context given as argument. */
353 ctx->A = A;
354 ctx->B = B;
355 ctx->C = C;
356 ctx->D = D;
357} 350}
358 351
359/* Feed data through a temporary buffer to call md5_hash_aligned_block() 352/* Feed data through a temporary buffer to call md5_hash_aligned_block()
360 * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. 353 * with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
361 * This function's internal buffer remembers previous data until it has 64 354 * This function's internal buffer remembers previous data until it has 64
362 * bytes worth to pass on. Call md5_end() to flush this buffer. */ 355 * bytes worth to pass on. Call md5_end() to flush this buffer. */
363void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) 356void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
364{ 357{
365 char *buf = (char *)buffer; 358 unsigned bufpos = ctx->total64 & 63;
359 unsigned remaining;
366 360
367 /* RFC 1321 specifies the possible length of the file up to 2^64 bits, 361 /* RFC 1321 specifies the possible length of the file up to 2^64 bits.
368 * Here we only track the number of bytes. */ 362 * Here we only track the number of bytes. */
369 ctx->total += len; 363 ctx->total64 += len;
370 364#if 0
371 /* Process all input. */ 365 remaining = 64 - bufpos;
372 while (len) { 366
373 unsigned i = 64 - ctx->buflen; 367 /* Hash whole blocks */
374 368 while (len >= remaining) {
375 /* Copy data into aligned buffer. */ 369 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
376 if (i > len) 370 buffer = (const char *)buffer + remaining;
377 i = len; 371 len -= remaining;
378 memcpy(ctx->buffer + ctx->buflen, buf, i); 372 remaining = 64;
379 len -= i; 373 bufpos = 0;
380 ctx->buflen += i; 374 md5_process_block64(ctx);
381 buf += i; 375 }
382 376
383 /* When buffer fills up, process it. */ 377 /* Save last, partial blosk */
384 if (ctx->buflen == 64) { 378 memcpy(ctx->wbuffer + bufpos, buffer, len);
385 md5_hash_block(ctx->buffer, ctx); 379#else
386 ctx->buflen = 0; 380 /* Tiny bit smaller code */
387 } 381 while (1) {
382 remaining = 64 - bufpos;
383 if (remaining > len)
384 remaining = len;
385 /* Copy data into aligned buffer */
386 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
387 len -= remaining;
388 buffer = (const char *)buffer + remaining;
389 bufpos += remaining;
390 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
391 bufpos -= 64;
392 if (bufpos != 0)
393 break;
394 /* Buffer is filled up, process it */
395 md5_process_block64(ctx);
396 /*bufpos = 0; - already is */
388 } 397 }
398#endif
389} 399}
390 400
391/* Process the remaining bytes in the buffer and put result from CTX 401/* Process the remaining bytes in the buffer and put result from CTX
@@ -393,26 +403,31 @@ void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
393 * endian byte order, so that a byte-wise output yields to the wanted 403 * endian byte order, so that a byte-wise output yields to the wanted
394 * ASCII representation of the message digest. 404 * ASCII representation of the message digest.
395 */ 405 */
396void FAST_FUNC md5_end(void *resbuf, md5_ctx_t *ctx) 406void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
397{ 407{
398 char *buf = ctx->buffer; 408 unsigned bufpos = ctx->total64 & 63;
399 int i; 409 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
400 410 ctx->wbuffer[bufpos++] = 0x80;
401 /* Pad data to block size. */ 411
402 buf[ctx->buflen++] = 0x80; 412 /* This loop iterates either once or twice, no more, no less */
403 memset(buf + ctx->buflen, 0, 128 - ctx->buflen); 413 while (1) {
404 414 unsigned remaining = 64 - bufpos;
405 /* Put the 64-bit file length in *bits* at the end of the buffer. */ 415 memset(ctx->wbuffer + bufpos, 0, remaining);
406 ctx->total <<= 3; 416 /* Do we have enough space for the length count? */
407 if (ctx->buflen > 56) 417 if (remaining >= 8) {
408 buf += 64; 418 /* Store the 64-bit counter of bits in the buffer in BE format */
409 for (i = 0; i < 8; i++) 419 uint64_t t = ctx->total64 << 3;
410 buf[56 + i] = ctx->total >> (i*8); 420 unsigned i;
411 421 for (i = 0; i < 8; i++) {
412 /* Process last bytes. */ 422 ctx->wbuffer[56 + i] = t;
413 if (buf != ctx->buffer) 423 t >>= 8;
414 md5_hash_block(ctx->buffer, ctx); 424 }
415 md5_hash_block(buf, ctx); 425 }
426 md5_process_block64(ctx);
427 if (remaining >= 8)
428 break;
429 bufpos = 0;
430 }
416 431
417 /* The MD5 result is in little endian byte order. 432 /* The MD5 result is in little endian byte order.
418 * We (ab)use the fact that A-D are consecutive in memory. 433 * We (ab)use the fact that A-D are consecutive in memory.