1 | /* |
2 | * RFC 1321 compliant MD5 implementation |
3 | * |
4 | * Copyright (C) 2006-2007 Christophe Devine |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License, version 2.1 as published by the Free Software Foundation. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
18 | * MA 02110-1301 USA |
19 | */ |
20 | /* |
21 | * The MD5 algorithm was designed by Ron Rivest in 1991. |
22 | * |
23 | * http://www.ietf.org/rfc/rfc1321.txt |
24 | */ |
25 | |
26 | // #include "xyssl/config.h" |
27 | |
28 | #if !defined(XYSSL_MD5_C) |
29 | |
30 | #include "md5.h" |
31 | |
32 | #include <string.h> |
33 | #include <stdio.h> |
34 | |
35 | /* |
36 | * 32-bit integer manipulation macros (little endian) |
37 | */ |
38 | #ifndef GET_ULONG_LE |
39 | #define GET_ULONG_LE(n,b,i) \ |
40 | { \ |
41 | (n) = ( (unsigned long) (b)[(i) ] ) \ |
42 | | ( (unsigned long) (b)[(i) + 1] << 8 ) \ |
43 | | ( (unsigned long) (b)[(i) + 2] << 16 ) \ |
44 | | ( (unsigned long) (b)[(i) + 3] << 24 ); \ |
45 | } |
46 | #endif |
47 | |
48 | #ifndef PUT_ULONG_LE |
49 | #define PUT_ULONG_LE(n,b,i) \ |
50 | { \ |
51 | (b)[(i) ] = (unsigned char) ( (n) ); \ |
52 | (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ |
53 | (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ |
54 | (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ |
55 | } |
56 | #endif |
57 | |
58 | /* |
59 | * MD5 context setup |
60 | */ |
61 | void md5_starts( md5_context *ctx ) |
62 | { |
63 | ctx->total[0] = 0; |
64 | ctx->total[1] = 0; |
65 | |
66 | ctx->state[0] = 0x67452301; |
67 | ctx->state[1] = 0xEFCDAB89; |
68 | ctx->state[2] = 0x98BADCFE; |
69 | ctx->state[3] = 0x10325476; |
70 | } |
71 | |
72 | static void md5_process( md5_context *ctx, unsigned char data[64] ) |
73 | { |
74 | unsigned long X[16], A, B, C, D; |
75 | |
76 | GET_ULONG_LE( X[ 0], data, 0 ); |
77 | GET_ULONG_LE( X[ 1], data, 4 ); |
78 | GET_ULONG_LE( X[ 2], data, 8 ); |
79 | GET_ULONG_LE( X[ 3], data, 12 ); |
80 | GET_ULONG_LE( X[ 4], data, 16 ); |
81 | GET_ULONG_LE( X[ 5], data, 20 ); |
82 | GET_ULONG_LE( X[ 6], data, 24 ); |
83 | GET_ULONG_LE( X[ 7], data, 28 ); |
84 | GET_ULONG_LE( X[ 8], data, 32 ); |
85 | GET_ULONG_LE( X[ 9], data, 36 ); |
86 | GET_ULONG_LE( X[10], data, 40 ); |
87 | GET_ULONG_LE( X[11], data, 44 ); |
88 | GET_ULONG_LE( X[12], data, 48 ); |
89 | GET_ULONG_LE( X[13], data, 52 ); |
90 | GET_ULONG_LE( X[14], data, 56 ); |
91 | GET_ULONG_LE( X[15], data, 60 ); |
92 | |
93 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) |
94 | |
95 | #define P(a,b,c,d,k,s,t) \ |
96 | { \ |
97 | a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ |
98 | } |
99 | |
100 | A = ctx->state[0]; |
101 | B = ctx->state[1]; |
102 | C = ctx->state[2]; |
103 | D = ctx->state[3]; |
104 | |
105 | #define F(x,y,z) (z ^ (x & (y ^ z))) |
106 | |
107 | P( A, B, C, D, 0, 7, 0xD76AA478 ); |
108 | P( D, A, B, C, 1, 12, 0xE8C7B756 ); |
109 | P( C, D, A, B, 2, 17, 0x242070DB ); |
110 | P( B, C, D, A, 3, 22, 0xC1BDCEEE ); |
111 | P( A, B, C, D, 4, 7, 0xF57C0FAF ); |
112 | P( D, A, B, C, 5, 12, 0x4787C62A ); |
113 | P( C, D, A, B, 6, 17, 0xA8304613 ); |
114 | P( B, C, D, A, 7, 22, 0xFD469501 ); |
115 | P( A, B, C, D, 8, 7, 0x698098D8 ); |
116 | P( D, A, B, C, 9, 12, 0x8B44F7AF ); |
117 | P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); |
118 | P( B, C, D, A, 11, 22, 0x895CD7BE ); |
119 | P( A, B, C, D, 12, 7, 0x6B901122 ); |
120 | P( D, A, B, C, 13, 12, 0xFD987193 ); |
121 | P( C, D, A, B, 14, 17, 0xA679438E ); |
122 | P( B, C, D, A, 15, 22, 0x49B40821 ); |
123 | |
124 | #undef F |
125 | |
126 | #define F(x,y,z) (y ^ (z & (x ^ y))) |
127 | |
128 | P( A, B, C, D, 1, 5, 0xF61E2562 ); |
129 | P( D, A, B, C, 6, 9, 0xC040B340 ); |
130 | P( C, D, A, B, 11, 14, 0x265E5A51 ); |
131 | P( B, C, D, A, 0, 20, 0xE9B6C7AA ); |
132 | P( A, B, C, D, 5, 5, 0xD62F105D ); |
133 | P( D, A, B, C, 10, 9, 0x02441453 ); |
134 | P( C, D, A, B, 15, 14, 0xD8A1E681 ); |
135 | P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); |
136 | P( A, B, C, D, 9, 5, 0x21E1CDE6 ); |
137 | P( D, A, B, C, 14, 9, 0xC33707D6 ); |
138 | P( C, D, A, B, 3, 14, 0xF4D50D87 ); |
139 | P( B, C, D, A, 8, 20, 0x455A14ED ); |
140 | P( A, B, C, D, 13, 5, 0xA9E3E905 ); |
141 | P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); |
142 | P( C, D, A, B, 7, 14, 0x676F02D9 ); |
143 | P( B, C, D, A, 12, 20, 0x8D2A4C8A ); |
144 | |
145 | #undef F |
146 | |
147 | #define F(x,y,z) (x ^ y ^ z) |
148 | |
149 | P( A, B, C, D, 5, 4, 0xFFFA3942 ); |
150 | P( D, A, B, C, 8, 11, 0x8771F681 ); |
151 | P( C, D, A, B, 11, 16, 0x6D9D6122 ); |
152 | P( B, C, D, A, 14, 23, 0xFDE5380C ); |
153 | P( A, B, C, D, 1, 4, 0xA4BEEA44 ); |
154 | P( D, A, B, C, 4, 11, 0x4BDECFA9 ); |
155 | P( C, D, A, B, 7, 16, 0xF6BB4B60 ); |
156 | P( B, C, D, A, 10, 23, 0xBEBFBC70 ); |
157 | P( A, B, C, D, 13, 4, 0x289B7EC6 ); |
158 | P( D, A, B, C, 0, 11, 0xEAA127FA ); |
159 | P( C, D, A, B, 3, 16, 0xD4EF3085 ); |
160 | P( B, C, D, A, 6, 23, 0x04881D05 ); |
161 | P( A, B, C, D, 9, 4, 0xD9D4D039 ); |
162 | P( D, A, B, C, 12, 11, 0xE6DB99E5 ); |
163 | P( C, D, A, B, 15, 16, 0x1FA27CF8 ); |
164 | P( B, C, D, A, 2, 23, 0xC4AC5665 ); |
165 | |
166 | #undef F |
167 | |
168 | #define F(x,y,z) (y ^ (x | ~z)) |
169 | |
170 | P( A, B, C, D, 0, 6, 0xF4292244 ); |
171 | P( D, A, B, C, 7, 10, 0x432AFF97 ); |
172 | P( C, D, A, B, 14, 15, 0xAB9423A7 ); |
173 | P( B, C, D, A, 5, 21, 0xFC93A039 ); |
174 | P( A, B, C, D, 12, 6, 0x655B59C3 ); |
175 | P( D, A, B, C, 3, 10, 0x8F0CCC92 ); |
176 | P( C, D, A, B, 10, 15, 0xFFEFF47D ); |
177 | P( B, C, D, A, 1, 21, 0x85845DD1 ); |
178 | P( A, B, C, D, 8, 6, 0x6FA87E4F ); |
179 | P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); |
180 | P( C, D, A, B, 6, 15, 0xA3014314 ); |
181 | P( B, C, D, A, 13, 21, 0x4E0811A1 ); |
182 | P( A, B, C, D, 4, 6, 0xF7537E82 ); |
183 | P( D, A, B, C, 11, 10, 0xBD3AF235 ); |
184 | P( C, D, A, B, 2, 15, 0x2AD7D2BB ); |
185 | P( B, C, D, A, 9, 21, 0xEB86D391 ); |
186 | |
187 | #undef F |
188 | |
189 | ctx->state[0] += A; |
190 | ctx->state[1] += B; |
191 | ctx->state[2] += C; |
192 | ctx->state[3] += D; |
193 | } |
194 | |
195 | /* |
196 | * MD5 process buffer |
197 | */ |
198 | void md5_update( md5_context *ctx, unsigned char *input, int ilen ) |
199 | { |
200 | int fill; |
201 | unsigned long left; |
202 | |
203 | if( ilen <= 0 ) |
204 | return; |
205 | |
206 | left = ctx->total[0] & 0x3F; |
207 | fill = 64 - left; |
208 | |
209 | ctx->total[0] += ilen; |
210 | ctx->total[0] &= 0xFFFFFFFF; |
211 | |
212 | if( ctx->total[0] < (unsigned long) ilen ) |
213 | ctx->total[1]++; |
214 | |
215 | if( left && ilen >= fill ) |
216 | { |
217 | memcpy( (void *) (ctx->buffer + left), |
218 | (void *) input, fill ); |
219 | md5_process( ctx, ctx->buffer ); |
220 | input += fill; |
221 | ilen -= fill; |
222 | left = 0; |
223 | } |
224 | |
225 | while( ilen >= 64 ) |
226 | { |
227 | md5_process( ctx, input ); |
228 | input += 64; |
229 | ilen -= 64; |
230 | } |
231 | |
232 | if( ilen > 0 ) |
233 | { |
234 | memcpy( (void *) (ctx->buffer + left), |
235 | (void *) input, ilen ); |
236 | } |
237 | } |
238 | |
239 | static const unsigned char md5_padding[64] = |
240 | { |
241 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
242 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
243 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
244 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
245 | }; |
246 | |
247 | /* |
248 | * MD5 final digest |
249 | */ |
250 | void md5_finish( md5_context *ctx, unsigned char output[16] ) |
251 | { |
252 | unsigned long last, padn; |
253 | unsigned long high, low; |
254 | unsigned char msglen[8]; |
255 | |
256 | high = ( ctx->total[0] >> 29 ) |
257 | | ( ctx->total[1] << 3 ); |
258 | low = ( ctx->total[0] << 3 ); |
259 | |
260 | PUT_ULONG_LE( low, msglen, 0 ); |
261 | PUT_ULONG_LE( high, msglen, 4 ); |
262 | |
263 | last = ctx->total[0] & 0x3F; |
264 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); |
265 | |
266 | md5_update( ctx, (unsigned char *) md5_padding, padn ); |
267 | md5_update( ctx, msglen, 8 ); |
268 | |
269 | PUT_ULONG_LE( ctx->state[0], output, 0 ); |
270 | PUT_ULONG_LE( ctx->state[1], output, 4 ); |
271 | PUT_ULONG_LE( ctx->state[2], output, 8 ); |
272 | PUT_ULONG_LE( ctx->state[3], output, 12 ); |
273 | } |
274 | |
275 | /* |
276 | * output = MD5( input buffer ) |
277 | */ |
278 | void md5( unsigned char *input, int ilen, unsigned char output[16] ) |
279 | { |
280 | md5_context ctx; |
281 | |
282 | md5_starts( &ctx ); |
283 | md5_update( &ctx, input, ilen ); |
284 | md5_finish( &ctx, output ); |
285 | |
286 | memset( &ctx, 0, sizeof( md5_context ) ); |
287 | } |
288 | |
289 | void md5_hex (char *input, int ilen, char output[32]) { |
290 | static char out[16], hcyf[16] = "0123456789abcdef" ; |
291 | int i; |
292 | |
293 | md5 ((unsigned char *) input, ilen, (unsigned char *) out); |
294 | for (i = 0; i < 16; i++) { |
295 | output[2*i] = hcyf[(out[i] >> 4) & 15]; |
296 | output[2*i+1] = hcyf[out[i] & 15]; |
297 | } |
298 | } |
299 | |
300 | /* |
301 | * output = MD5( file contents ) |
302 | */ |
303 | int md5_file( char *path, unsigned char output[16] ) |
304 | { |
305 | FILE *f; |
306 | size_t n; |
307 | md5_context ctx; |
308 | unsigned char buf[1024]; |
309 | |
310 | if( ( f = fopen( path, "rb" ) ) == NULL ) |
311 | return( 1 ); |
312 | |
313 | md5_starts( &ctx ); |
314 | |
315 | while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) |
316 | md5_update( &ctx, buf, (int) n ); |
317 | |
318 | md5_finish( &ctx, output ); |
319 | |
320 | memset( &ctx, 0, sizeof( md5_context ) ); |
321 | |
322 | if( ferror( f ) != 0 ) |
323 | { |
324 | fclose( f ); |
325 | return( 2 ); |
326 | } |
327 | |
328 | fclose( f ); |
329 | return( 0 ); |
330 | } |
331 | |
332 | /* |
333 | * MD5 HMAC context setup |
334 | */ |
335 | void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen ) |
336 | { |
337 | int i; |
338 | unsigned char sum[16]; |
339 | |
340 | if( keylen > 64 ) |
341 | { |
342 | md5( key, keylen, sum ); |
343 | keylen = 16; |
344 | key = sum; |
345 | } |
346 | |
347 | memset( ctx->ipad, 0x36, 64 ); |
348 | memset( ctx->opad, 0x5C, 64 ); |
349 | |
350 | for( i = 0; i < keylen; i++ ) |
351 | { |
352 | ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); |
353 | ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); |
354 | } |
355 | |
356 | md5_starts( ctx ); |
357 | md5_update( ctx, ctx->ipad, 64 ); |
358 | |
359 | memset( sum, 0, sizeof( sum ) ); |
360 | } |
361 | |
362 | /* |
363 | * MD5 HMAC process buffer |
364 | */ |
365 | void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen ) |
366 | { |
367 | md5_update( ctx, input, ilen ); |
368 | } |
369 | |
370 | /* |
371 | * MD5 HMAC final digest |
372 | */ |
373 | void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ) |
374 | { |
375 | unsigned char tmpbuf[16]; |
376 | |
377 | md5_finish( ctx, tmpbuf ); |
378 | md5_starts( ctx ); |
379 | md5_update( ctx, ctx->opad, 64 ); |
380 | md5_update( ctx, tmpbuf, 16 ); |
381 | md5_finish( ctx, output ); |
382 | |
383 | memset( tmpbuf, 0, sizeof( tmpbuf ) ); |
384 | } |
385 | |
386 | /* |
387 | * output = HMAC-MD5( hmac key, input buffer ) |
388 | */ |
389 | void md5_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen, |
390 | unsigned char output[16] ) |
391 | { |
392 | md5_context ctx; |
393 | |
394 | md5_hmac_starts( &ctx, key, keylen ); |
395 | md5_hmac_update( &ctx, input, ilen ); |
396 | md5_hmac_finish( &ctx, output ); |
397 | |
398 | memset( &ctx, 0, sizeof( md5_context ) ); |
399 | } |
400 | |
401 | #if defined(XYSSL_SELF_TEST) |
402 | |
403 | /* |
404 | * RFC 1321 test vectors |
405 | */ |
406 | static const char md5_test_str[7][81] = |
407 | { |
408 | { "" }, |
409 | { "a" }, |
410 | { "abc" }, |
411 | { "message digest" }, |
412 | { "abcdefghijklmnopqrstuvwxyz" }, |
413 | { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, |
414 | { "12345678901234567890123456789012345678901234567890123456789012" \ |
415 | "345678901234567890" } |
416 | }; |
417 | |
418 | static const unsigned char md5_test_sum[7][16] = |
419 | { |
420 | { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, |
421 | 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, |
422 | { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, |
423 | 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, |
424 | { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, |
425 | 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, |
426 | { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, |
427 | 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, |
428 | { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, |
429 | 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, |
430 | { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, |
431 | 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, |
432 | { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, |
433 | 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } |
434 | }; |
435 | |
436 | /* |
437 | * Checkup routine |
438 | */ |
439 | int md5_self_test( int verbose ) |
440 | { |
441 | int i; |
442 | unsigned char md5sum[16]; |
443 | |
444 | for( i = 0; i < 7; i++ ) |
445 | { |
446 | if( verbose != 0 ) |
447 | printf( " MD5 test #%d: " , i + 1 ); |
448 | |
449 | md5( (unsigned char *) md5_test_str[i], |
450 | strlen( md5_test_str[i] ), md5sum ); |
451 | |
452 | if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) |
453 | { |
454 | if( verbose != 0 ) |
455 | printf( "failed\n" ); |
456 | |
457 | return( 1 ); |
458 | } |
459 | |
460 | if( verbose != 0 ) |
461 | printf( "passed\n" ); |
462 | } |
463 | |
464 | if( verbose != 0 ) |
465 | printf( "\n" ); |
466 | |
467 | return( 0 ); |
468 | } |
469 | |
470 | #endif |
471 | |
472 | #endif |
473 | |