1 /* This file is not used by busybox right now.
2 * However, the code here seems to be a tiny bit smaller
3 * than one in md5.c. Need to investigate which one
5 * Hint: grep for md5prime to find places where you can switch
10 * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
12 * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
15 * License to copy and use this software is granted provided that it
16 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
17 * Algorithm" in all material mentioning or referencing this software
20 * License is also granted to make and use derivative works provided
21 * that such works are identified as "derived from the RSA Data
22 * Security, Inc. MD5 Message-Digest Algorithm" in all material
23 * mentioning or referencing the derived work.
25 * RSA Data Security, Inc. makes no representations concerning either
26 * the merchantability of this software or the suitability of this
27 * software for any particular purpose. It is provided "as is"
28 * without express or implied warranty of any kind.
30 * These notices must be retained in any copies of any part of this
31 * documentation and/or software.
33 * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
35 * This code is the same as the code published by RSA Inc. It has been
36 * edited for clarity and style only.
38 * ----------------------------------------------------------------------------
39 * The md5_crypt() function was taken from freeBSD's libcrypt and contains
41 * "THE BEER-WARE LICENSE" (Revision 42):
42 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
43 * can do whatever you want with this stuff. If we meet some day, and you think
44 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
46 * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
48 * ----------------------------------------------------------------------------
49 * On April 19th, 2001 md5_crypt() was modified to make it reentrant
50 * by Erik Andersen <andersen@uclibc.org>
52 * June 28, 2001 Manuel Novoa III
54 * "Un-inlined" code using loops and static const tables in order to
55 * reduce generated code size (on i386 from approx 4k to approx 2.5k).
57 * June 29, 2001 Manuel Novoa III
59 * Completely removed static PADDING array.
61 * Reintroduced the loop unrolling in md5_transform and added the
62 * MD5_SIZE_VS_SPEED option for configurability. Define below as:
63 * 0 fully unrolled loops
64 * 1 partially unrolled (4 ops per loop)
65 * 2 no unrolling -- introduces the need to swap 4 variables (slow)
66 * 3 no unrolling and all 4 loops merged into one with switch
67 * in each loop (glacial)
68 * On i386, sizes are roughly (-Os -fno-builtin):
69 * 0: 3k 1: 2.5k 2: 2.2k 3: 2k
71 * Since SuSv3 does not require crypt_r, modified again August 7, 2002
72 * by Erik Andersen to remove reentrance stuff...
77 /* 1: fastest, 3: smallest */
78 #if CONFIG_MD5_SIZE_VS_SPEED < 1
79 # define MD5_SIZE_VS_SPEED 1
80 #elif CONFIG_MD5_SIZE_VS_SPEED > 3
81 # define MD5_SIZE_VS_SPEED 3
83 # define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED
87 #define memcpy32_cpu2le memcpy
88 #define memcpy32_le2cpu memcpy
90 /* Encodes input (uint32_t) into output (unsigned char).
91 * Assumes len is a multiple of 4. */
93 memcpy32_cpu2le(unsigned char *output
, uint32_t *input
, unsigned len
)
96 for (i
= 0, j
= 0; j
< len
; i
++, j
+= 4) {
98 output
[j
+1] = (input
[i
] >> 8);
99 output
[j
+2] = (input
[i
] >> 16);
100 output
[j
+3] = (input
[i
] >> 24);
103 /* Decodes input (unsigned char) into output (uint32_t).
104 * Assumes len is a multiple of 4. */
106 memcpy32_le2cpu(uint32_t *output
, const unsigned char *input
, unsigned len
)
109 for (i
= 0, j
= 0; j
< len
; i
++, j
+= 4)
110 output
[i
] = ((uint32_t)input
[j
])
111 | (((uint32_t)input
[j
+1]) << 8)
112 | (((uint32_t)input
[j
+2]) << 16)
113 | (((uint32_t)input
[j
+3]) << 24);
117 /* F, G, H and I are basic MD5 functions. */
118 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
119 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
120 #define H(x, y, z) ((x) ^ (y) ^ (z))
121 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
123 /* rotl32 rotates x left n bits. */
124 #define rotl32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
127 * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
128 * Rotation is separate from addition to prevent recomputation.
130 #define FF(a, b, c, d, x, s, ac) { \
131 (a) += F((b), (c), (d)) + (x) + (uint32_t)(ac); \
132 (a) = rotl32((a), (s)); \
135 #define GG(a, b, c, d, x, s, ac) { \
136 (a) += G((b), (c), (d)) + (x) + (uint32_t)(ac); \
137 (a) = rotl32((a), (s)); \
140 #define HH(a, b, c, d, x, s, ac) { \
141 (a) += H((b), (c), (d)) + (x) + (uint32_t)(ac); \
142 (a) = rotl32((a), (s)); \
145 #define II(a, b, c, d, x, s, ac) { \
146 (a) += I((b), (c), (d)) + (x) + (uint32_t)(ac); \
147 (a) = rotl32((a), (s)); \
151 /* MD5 basic transformation. Transforms state based on block. */
152 static void md5_transform(uint32_t state
[4], const unsigned char block
[64])
154 uint32_t a
, b
, c
, d
, x
[16];
155 #if MD5_SIZE_VS_SPEED > 1
157 const unsigned char *ps
;
159 static const unsigned char S
[] = {
165 #endif /* MD5_SIZE_VS_SPEED > 1 */
167 #if MD5_SIZE_VS_SPEED > 0
169 const unsigned char *pp
;
172 static const uint32_t C
[] = {
174 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
175 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
176 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
177 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
179 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
180 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
181 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
182 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
184 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
185 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
186 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
187 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
189 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
190 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
191 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
192 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
194 static const unsigned char P
[] = {
195 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
196 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
197 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
198 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
201 #endif /* MD5_SIZE_VS_SPEED > 0 */
203 memcpy32_le2cpu(x
, block
, 64);
210 #if MD5_SIZE_VS_SPEED > 2
214 for (i
= 0; i
< 64; i
++) {
215 if ((i
& 0x0f) == 0) ps
+= 4;
231 temp
+= x
[*pp
++] + *pc
++;
232 temp
= rotl32(temp
, ps
[i
& 3]);
234 a
= d
; d
= c
; c
= b
; b
= temp
;
236 #elif MD5_SIZE_VS_SPEED > 1
241 for (i
= 0; i
< 16; i
++) {
242 FF(a
, b
, c
, d
, x
[*pp
], ps
[i
& 0x3], *pc
); pp
++; pc
++;
243 temp
= d
; d
= c
; c
= b
; b
= a
; a
= temp
;
247 for (; i
< 32; i
++) {
248 GG(a
, b
, c
, d
, x
[*pp
], ps
[i
& 0x3], *pc
); pp
++; pc
++;
249 temp
= d
; d
= c
; c
= b
; b
= a
; a
= temp
;
253 for (; i
< 48; i
++) {
254 HH(a
, b
, c
, d
, x
[*pp
], ps
[i
& 0x3], *pc
); pp
++; pc
++;
255 temp
= d
; d
= c
; c
= b
; b
= a
; a
= temp
;
259 for (; i
< 64; i
++) {
260 II(a
, b
, c
, d
, x
[*pp
], ps
[i
& 0x3], *pc
); pp
++; pc
++;
261 temp
= d
; d
= c
; c
= b
; b
= a
; a
= temp
;
263 #elif MD5_SIZE_VS_SPEED > 0
267 for (i
= 0; i
< 4; i
++) {
268 FF(a
, b
, c
, d
, x
[*pp
], 7, *pc
); pp
++; pc
++;
269 FF(d
, a
, b
, c
, x
[*pp
], 12, *pc
); pp
++; pc
++;
270 FF(c
, d
, a
, b
, x
[*pp
], 17, *pc
); pp
++; pc
++;
271 FF(b
, c
, d
, a
, x
[*pp
], 22, *pc
); pp
++; pc
++;
274 for (i
= 0; i
< 4; i
++) {
275 GG(a
, b
, c
, d
, x
[*pp
], 5, *pc
); pp
++; pc
++;
276 GG(d
, a
, b
, c
, x
[*pp
], 9, *pc
); pp
++; pc
++;
277 GG(c
, d
, a
, b
, x
[*pp
], 14, *pc
); pp
++; pc
++;
278 GG(b
, c
, d
, a
, x
[*pp
], 20, *pc
); pp
++; pc
++;
281 for (i
= 0; i
< 4; i
++) {
282 HH(a
, b
, c
, d
, x
[*pp
], 4, *pc
); pp
++; pc
++;
283 HH(d
, a
, b
, c
, x
[*pp
], 11, *pc
); pp
++; pc
++;
284 HH(c
, d
, a
, b
, x
[*pp
], 16, *pc
); pp
++; pc
++;
285 HH(b
, c
, d
, a
, x
[*pp
], 23, *pc
); pp
++; pc
++;
288 for (i
= 0; i
< 4; i
++) {
289 II(a
, b
, c
, d
, x
[*pp
], 6, *pc
); pp
++; pc
++;
290 II(d
, a
, b
, c
, x
[*pp
], 10, *pc
); pp
++; pc
++;
291 II(c
, d
, a
, b
, x
[*pp
], 15, *pc
); pp
++; pc
++;
292 II(b
, c
, d
, a
, x
[*pp
], 21, *pc
); pp
++; pc
++;
300 FF(a
, b
, c
, d
, x
[ 0], S11
, 0xd76aa478); /* 1 */
301 FF(d
, a
, b
, c
, x
[ 1], S12
, 0xe8c7b756); /* 2 */
302 FF(c
, d
, a
, b
, x
[ 2], S13
, 0x242070db); /* 3 */
303 FF(b
, c
, d
, a
, x
[ 3], S14
, 0xc1bdceee); /* 4 */
304 FF(a
, b
, c
, d
, x
[ 4], S11
, 0xf57c0faf); /* 5 */
305 FF(d
, a
, b
, c
, x
[ 5], S12
, 0x4787c62a); /* 6 */
306 FF(c
, d
, a
, b
, x
[ 6], S13
, 0xa8304613); /* 7 */
307 FF(b
, c
, d
, a
, x
[ 7], S14
, 0xfd469501); /* 8 */
308 FF(a
, b
, c
, d
, x
[ 8], S11
, 0x698098d8); /* 9 */
309 FF(d
, a
, b
, c
, x
[ 9], S12
, 0x8b44f7af); /* 10 */
310 FF(c
, d
, a
, b
, x
[10], S13
, 0xffff5bb1); /* 11 */
311 FF(b
, c
, d
, a
, x
[11], S14
, 0x895cd7be); /* 12 */
312 FF(a
, b
, c
, d
, x
[12], S11
, 0x6b901122); /* 13 */
313 FF(d
, a
, b
, c
, x
[13], S12
, 0xfd987193); /* 14 */
314 FF(c
, d
, a
, b
, x
[14], S13
, 0xa679438e); /* 15 */
315 FF(b
, c
, d
, a
, x
[15], S14
, 0x49b40821); /* 16 */
321 GG(a
, b
, c
, d
, x
[ 1], S21
, 0xf61e2562); /* 17 */
322 GG(d
, a
, b
, c
, x
[ 6], S22
, 0xc040b340); /* 18 */
323 GG(c
, d
, a
, b
, x
[11], S23
, 0x265e5a51); /* 19 */
324 GG(b
, c
, d
, a
, x
[ 0], S24
, 0xe9b6c7aa); /* 20 */
325 GG(a
, b
, c
, d
, x
[ 5], S21
, 0xd62f105d); /* 21 */
326 GG(d
, a
, b
, c
, x
[10], S22
, 0x2441453); /* 22 */
327 GG(c
, d
, a
, b
, x
[15], S23
, 0xd8a1e681); /* 23 */
328 GG(b
, c
, d
, a
, x
[ 4], S24
, 0xe7d3fbc8); /* 24 */
329 GG(a
, b
, c
, d
, x
[ 9], S21
, 0x21e1cde6); /* 25 */
330 GG(d
, a
, b
, c
, x
[14], S22
, 0xc33707d6); /* 26 */
331 GG(c
, d
, a
, b
, x
[ 3], S23
, 0xf4d50d87); /* 27 */
332 GG(b
, c
, d
, a
, x
[ 8], S24
, 0x455a14ed); /* 28 */
333 GG(a
, b
, c
, d
, x
[13], S21
, 0xa9e3e905); /* 29 */
334 GG(d
, a
, b
, c
, x
[ 2], S22
, 0xfcefa3f8); /* 30 */
335 GG(c
, d
, a
, b
, x
[ 7], S23
, 0x676f02d9); /* 31 */
336 GG(b
, c
, d
, a
, x
[12], S24
, 0x8d2a4c8a); /* 32 */
342 HH(a
, b
, c
, d
, x
[ 5], S31
, 0xfffa3942); /* 33 */
343 HH(d
, a
, b
, c
, x
[ 8], S32
, 0x8771f681); /* 34 */
344 HH(c
, d
, a
, b
, x
[11], S33
, 0x6d9d6122); /* 35 */
345 HH(b
, c
, d
, a
, x
[14], S34
, 0xfde5380c); /* 36 */
346 HH(a
, b
, c
, d
, x
[ 1], S31
, 0xa4beea44); /* 37 */
347 HH(d
, a
, b
, c
, x
[ 4], S32
, 0x4bdecfa9); /* 38 */
348 HH(c
, d
, a
, b
, x
[ 7], S33
, 0xf6bb4b60); /* 39 */
349 HH(b
, c
, d
, a
, x
[10], S34
, 0xbebfbc70); /* 40 */
350 HH(a
, b
, c
, d
, x
[13], S31
, 0x289b7ec6); /* 41 */
351 HH(d
, a
, b
, c
, x
[ 0], S32
, 0xeaa127fa); /* 42 */
352 HH(c
, d
, a
, b
, x
[ 3], S33
, 0xd4ef3085); /* 43 */
353 HH(b
, c
, d
, a
, x
[ 6], S34
, 0x4881d05); /* 44 */
354 HH(a
, b
, c
, d
, x
[ 9], S31
, 0xd9d4d039); /* 45 */
355 HH(d
, a
, b
, c
, x
[12], S32
, 0xe6db99e5); /* 46 */
356 HH(c
, d
, a
, b
, x
[15], S33
, 0x1fa27cf8); /* 47 */
357 HH(b
, c
, d
, a
, x
[ 2], S34
, 0xc4ac5665); /* 48 */
363 II(a
, b
, c
, d
, x
[ 0], S41
, 0xf4292244); /* 49 */
364 II(d
, a
, b
, c
, x
[ 7], S42
, 0x432aff97); /* 50 */
365 II(c
, d
, a
, b
, x
[14], S43
, 0xab9423a7); /* 51 */
366 II(b
, c
, d
, a
, x
[ 5], S44
, 0xfc93a039); /* 52 */
367 II(a
, b
, c
, d
, x
[12], S41
, 0x655b59c3); /* 53 */
368 II(d
, a
, b
, c
, x
[ 3], S42
, 0x8f0ccc92); /* 54 */
369 II(c
, d
, a
, b
, x
[10], S43
, 0xffeff47d); /* 55 */
370 II(b
, c
, d
, a
, x
[ 1], S44
, 0x85845dd1); /* 56 */
371 II(a
, b
, c
, d
, x
[ 8], S41
, 0x6fa87e4f); /* 57 */
372 II(d
, a
, b
, c
, x
[15], S42
, 0xfe2ce6e0); /* 58 */
373 II(c
, d
, a
, b
, x
[ 6], S43
, 0xa3014314); /* 59 */
374 II(b
, c
, d
, a
, x
[13], S44
, 0x4e0811a1); /* 60 */
375 II(a
, b
, c
, d
, x
[ 4], S41
, 0xf7537e82); /* 61 */
376 II(d
, a
, b
, c
, x
[11], S42
, 0xbd3af235); /* 62 */
377 II(c
, d
, a
, b
, x
[ 2], S43
, 0x2ad7d2bb); /* 63 */
378 II(b
, c
, d
, a
, x
[ 9], S44
, 0xeb86d391); /* 64 */
386 /* Zeroize sensitive information. */
387 memset(x
, 0, sizeof(x
));
391 /* MD5 initialization. */
392 void FAST_FUNC
md5_begin(md5_ctx_t
*context
)
394 context
->count
[0] = context
->count
[1] = 0;
395 /* Load magic initialization constants. */
396 context
->state
[0] = 0x67452301;
397 context
->state
[1] = 0xefcdab89;
398 context
->state
[2] = 0x98badcfe;
399 context
->state
[3] = 0x10325476;
403 * MD5 block update operation. Continues an MD5 message-digest
404 * operation, processing another message block, and updating
407 void FAST_FUNC
md5_hash(const void *buffer
, size_t inputLen
, md5_ctx_t
*context
)
409 unsigned i
, idx
, partLen
;
410 const unsigned char *input
= buffer
;
412 /* Compute number of bytes mod 64 */
413 idx
= (context
->count
[0] >> 3) & 0x3F;
415 /* Update number of bits */
416 context
->count
[0] += (inputLen
<< 3);
417 if (context
->count
[0] < (inputLen
<< 3))
419 context
->count
[1] += (inputLen
>> 29);
421 /* Transform as many times as possible. */
424 if (inputLen
>= partLen
) {
425 memcpy(&context
->buffer
[idx
], input
, partLen
);
426 md5_transform(context
->state
, context
->buffer
);
427 for (i
= partLen
; i
+ 63 < inputLen
; i
+= 64)
428 md5_transform(context
->state
, &input
[i
]);
432 /* Buffer remaining input */
433 memcpy(&context
->buffer
[idx
], &input
[i
], inputLen
- i
);
437 * MD5 finalization. Ends an MD5 message-digest operation,
438 * writing the message digest.
440 void FAST_FUNC
md5_end(void *digest
, md5_ctx_t
*context
)
442 unsigned idx
, padLen
;
443 unsigned char bits
[8];
444 unsigned char padding
[64];
446 /* Add padding followed by original length. */
447 memset(padding
, 0, sizeof(padding
));
449 /* save number of bits */
450 memcpy32_cpu2le(bits
, context
->count
, 8);
451 /* pad out to 56 mod 64 */
452 idx
= (context
->count
[0] >> 3) & 0x3f;
453 padLen
= (idx
< 56) ? (56 - idx
) : (120 - idx
);
454 md5_hash(padding
, padLen
, context
);
455 /* append length (before padding) */
456 md5_hash(bits
, 8, context
);
458 /* Store state in digest */
459 memcpy32_cpu2le(digest
, context
->state
, 16);