2 * RFC 1321 compliant MD5 implementation
4 * Copyright (C) 2006-2007 Christophe Devine
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.
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.
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,
21 * The MD5 algorithm was designed by Ron Rivest in 1991.
22 * From the XYSSL project.
24 * http://www.ietf.org/rfc/rfc1321.txt
32 * 32-bit integer manipulation macros (little endian)
35 #define GET_ULONG_LE(n,b,i) \
37 (n) = ( (unsigned long) (b)[(i) ] ) \
38 | ( (unsigned long) (b)[(i) + 1] << 8 ) \
39 | ( (unsigned long) (b)[(i) + 2] << 16 ) \
40 | ( (unsigned long) (b)[(i) + 3] << 24 ); \
45 #define PUT_ULONG_LE(n,b,i) \
47 (b)[(i) ] = (unsigned char) ( (n) ); \
48 (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
49 (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
50 (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
57 void md5_starts( md5_context
*ctx
)
62 ctx
->state
[0] = 0x67452301;
63 ctx
->state
[1] = 0xEFCDAB89;
64 ctx
->state
[2] = 0x98BADCFE;
65 ctx
->state
[3] = 0x10325476;
68 static void md5_process( md5_context
*ctx
, unsigned char data
[64] )
70 unsigned long X
[16], A
, B
, C
, D
;
72 GET_ULONG_LE( X
[ 0], data
, 0 );
73 GET_ULONG_LE( X
[ 1], data
, 4 );
74 GET_ULONG_LE( X
[ 2], data
, 8 );
75 GET_ULONG_LE( X
[ 3], data
, 12 );
76 GET_ULONG_LE( X
[ 4], data
, 16 );
77 GET_ULONG_LE( X
[ 5], data
, 20 );
78 GET_ULONG_LE( X
[ 6], data
, 24 );
79 GET_ULONG_LE( X
[ 7], data
, 28 );
80 GET_ULONG_LE( X
[ 8], data
, 32 );
81 GET_ULONG_LE( X
[ 9], data
, 36 );
82 GET_ULONG_LE( X
[10], data
, 40 );
83 GET_ULONG_LE( X
[11], data
, 44 );
84 GET_ULONG_LE( X
[12], data
, 48 );
85 GET_ULONG_LE( X
[13], data
, 52 );
86 GET_ULONG_LE( X
[14], data
, 56 );
87 GET_ULONG_LE( X
[15], data
, 60 );
89 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
91 #define P(a,b,c,d,k,s,t) \
93 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
101 #define F(x,y,z) (z ^ (x & (y ^ z)))
103 P( A
, B
, C
, D
, 0, 7, 0xD76AA478 );
104 P( D
, A
, B
, C
, 1, 12, 0xE8C7B756 );
105 P( C
, D
, A
, B
, 2, 17, 0x242070DB );
106 P( B
, C
, D
, A
, 3, 22, 0xC1BDCEEE );
107 P( A
, B
, C
, D
, 4, 7, 0xF57C0FAF );
108 P( D
, A
, B
, C
, 5, 12, 0x4787C62A );
109 P( C
, D
, A
, B
, 6, 17, 0xA8304613 );
110 P( B
, C
, D
, A
, 7, 22, 0xFD469501 );
111 P( A
, B
, C
, D
, 8, 7, 0x698098D8 );
112 P( D
, A
, B
, C
, 9, 12, 0x8B44F7AF );
113 P( C
, D
, A
, B
, 10, 17, 0xFFFF5BB1 );
114 P( B
, C
, D
, A
, 11, 22, 0x895CD7BE );
115 P( A
, B
, C
, D
, 12, 7, 0x6B901122 );
116 P( D
, A
, B
, C
, 13, 12, 0xFD987193 );
117 P( C
, D
, A
, B
, 14, 17, 0xA679438E );
118 P( B
, C
, D
, A
, 15, 22, 0x49B40821 );
122 #define F(x,y,z) (y ^ (z & (x ^ y)))
124 P( A
, B
, C
, D
, 1, 5, 0xF61E2562 );
125 P( D
, A
, B
, C
, 6, 9, 0xC040B340 );
126 P( C
, D
, A
, B
, 11, 14, 0x265E5A51 );
127 P( B
, C
, D
, A
, 0, 20, 0xE9B6C7AA );
128 P( A
, B
, C
, D
, 5, 5, 0xD62F105D );
129 P( D
, A
, B
, C
, 10, 9, 0x02441453 );
130 P( C
, D
, A
, B
, 15, 14, 0xD8A1E681 );
131 P( B
, C
, D
, A
, 4, 20, 0xE7D3FBC8 );
132 P( A
, B
, C
, D
, 9, 5, 0x21E1CDE6 );
133 P( D
, A
, B
, C
, 14, 9, 0xC33707D6 );
134 P( C
, D
, A
, B
, 3, 14, 0xF4D50D87 );
135 P( B
, C
, D
, A
, 8, 20, 0x455A14ED );
136 P( A
, B
, C
, D
, 13, 5, 0xA9E3E905 );
137 P( D
, A
, B
, C
, 2, 9, 0xFCEFA3F8 );
138 P( C
, D
, A
, B
, 7, 14, 0x676F02D9 );
139 P( B
, C
, D
, A
, 12, 20, 0x8D2A4C8A );
143 #define F(x,y,z) (x ^ y ^ z)
145 P( A
, B
, C
, D
, 5, 4, 0xFFFA3942 );
146 P( D
, A
, B
, C
, 8, 11, 0x8771F681 );
147 P( C
, D
, A
, B
, 11, 16, 0x6D9D6122 );
148 P( B
, C
, D
, A
, 14, 23, 0xFDE5380C );
149 P( A
, B
, C
, D
, 1, 4, 0xA4BEEA44 );
150 P( D
, A
, B
, C
, 4, 11, 0x4BDECFA9 );
151 P( C
, D
, A
, B
, 7, 16, 0xF6BB4B60 );
152 P( B
, C
, D
, A
, 10, 23, 0xBEBFBC70 );
153 P( A
, B
, C
, D
, 13, 4, 0x289B7EC6 );
154 P( D
, A
, B
, C
, 0, 11, 0xEAA127FA );
155 P( C
, D
, A
, B
, 3, 16, 0xD4EF3085 );
156 P( B
, C
, D
, A
, 6, 23, 0x04881D05 );
157 P( A
, B
, C
, D
, 9, 4, 0xD9D4D039 );
158 P( D
, A
, B
, C
, 12, 11, 0xE6DB99E5 );
159 P( C
, D
, A
, B
, 15, 16, 0x1FA27CF8 );
160 P( B
, C
, D
, A
, 2, 23, 0xC4AC5665 );
164 #define F(x,y,z) (y ^ (x | ~z))
166 P( A
, B
, C
, D
, 0, 6, 0xF4292244 );
167 P( D
, A
, B
, C
, 7, 10, 0x432AFF97 );
168 P( C
, D
, A
, B
, 14, 15, 0xAB9423A7 );
169 P( B
, C
, D
, A
, 5, 21, 0xFC93A039 );
170 P( A
, B
, C
, D
, 12, 6, 0x655B59C3 );
171 P( D
, A
, B
, C
, 3, 10, 0x8F0CCC92 );
172 P( C
, D
, A
, B
, 10, 15, 0xFFEFF47D );
173 P( B
, C
, D
, A
, 1, 21, 0x85845DD1 );
174 P( A
, B
, C
, D
, 8, 6, 0x6FA87E4F );
175 P( D
, A
, B
, C
, 15, 10, 0xFE2CE6E0 );
176 P( C
, D
, A
, B
, 6, 15, 0xA3014314 );
177 P( B
, C
, D
, A
, 13, 21, 0x4E0811A1 );
178 P( A
, B
, C
, D
, 4, 6, 0xF7537E82 );
179 P( D
, A
, B
, C
, 11, 10, 0xBD3AF235 );
180 P( C
, D
, A
, B
, 2, 15, 0x2AD7D2BB );
181 P( B
, C
, D
, A
, 9, 21, 0xEB86D391 );
194 void md5_update( md5_context
*ctx
, unsigned char *input
, int ilen
)
202 left
= ctx
->total
[0] & 0x3F;
205 ctx
->total
[0] += ilen
;
206 ctx
->total
[0] &= 0xFFFFFFFF;
208 if( ctx
->total
[0] < (unsigned long) ilen
)
211 if( left
&& ilen
>= fill
)
213 memcpy( (void *) (ctx
->buffer
+ left
),
214 (void *) input
, fill
);
215 md5_process( ctx
, ctx
->buffer
);
223 md5_process( ctx
, input
);
230 memcpy( (void *) (ctx
->buffer
+ left
),
231 (void *) input
, ilen
);
235 static const unsigned char md5_padding
[64] =
237 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
238 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
239 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
240 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
246 void md5_finish( md5_context
*ctx
, unsigned char output
[16] )
248 unsigned long last
, padn
;
249 unsigned long high
, low
;
250 unsigned char msglen
[8];
252 high
= ( ctx
->total
[0] >> 29 )
253 | ( ctx
->total
[1] << 3 );
254 low
= ( ctx
->total
[0] << 3 );
256 PUT_ULONG_LE( low
, msglen
, 0 );
257 PUT_ULONG_LE( high
, msglen
, 4 );
259 last
= ctx
->total
[0] & 0x3F;
260 padn
= ( last
< 56 ) ? ( 56 - last
) : ( 120 - last
);
262 md5_update( ctx
, (unsigned char *) md5_padding
, padn
);
263 md5_update( ctx
, msglen
, 8 );
265 PUT_ULONG_LE( ctx
->state
[0], output
, 0 );
266 PUT_ULONG_LE( ctx
->state
[1], output
, 4 );
267 PUT_ULONG_LE( ctx
->state
[2], output
, 8 );
268 PUT_ULONG_LE( ctx
->state
[3], output
, 12 );
272 * output = MD5( input buffer )
274 void md5( unsigned char *input
, int ilen
, unsigned char output
[16] )
279 md5_update( &ctx
, input
, ilen
);
280 md5_finish( &ctx
, output
);
282 memset( &ctx
, 0, sizeof( md5_context
) );
286 * output = MD5( file contents )
288 int md5_file( char *path
, unsigned char output
[16] )
293 unsigned char buf
[1024];
295 if( ( f
= fopen( path
, "rb" ) ) == NULL
)
300 while( ( n
= fread( buf
, 1, sizeof( buf
), f
) ) > 0 )
301 md5_update( &ctx
, buf
, (int) n
);
303 md5_finish( &ctx
, output
);
305 memset( &ctx
, 0, sizeof( md5_context
) );
307 if( ferror( f
) != 0 )
318 * MD5 HMAC context setup
320 void md5_hmac_starts( md5_context
*ctx
, unsigned char *key
, int keylen
)
323 unsigned char sum
[16];
327 md5( key
, keylen
, sum
);
332 memset( ctx
->ipad
, 0x36, 64 );
333 memset( ctx
->opad
, 0x5C, 64 );
335 for( i
= 0; i
< keylen
; i
++ )
337 ctx
->ipad
[i
] = (unsigned char)( ctx
->ipad
[i
] ^ key
[i
] );
338 ctx
->opad
[i
] = (unsigned char)( ctx
->opad
[i
] ^ key
[i
] );
342 md5_update( ctx
, ctx
->ipad
, 64 );
344 memset( sum
, 0, sizeof( sum
) );
348 * MD5 HMAC process buffer
350 void md5_hmac_update( md5_context
*ctx
, unsigned char *input
, int ilen
)
352 md5_update( ctx
, input
, ilen
);
356 * MD5 HMAC final digest
358 void md5_hmac_finish( md5_context
*ctx
, unsigned char output
[16] )
360 unsigned char tmpbuf
[16];
362 md5_finish( ctx
, tmpbuf
);
364 md5_update( ctx
, ctx
->opad
, 64 );
365 md5_update( ctx
, tmpbuf
, 16 );
366 md5_finish( ctx
, output
);
368 memset( tmpbuf
, 0, sizeof( tmpbuf
) );
372 * output = HMAC-MD5( hmac key, input buffer )
374 void md5_hmac( unsigned char *key
, int keylen
, unsigned char *input
, int ilen
,
375 unsigned char output
[16] )
379 md5_hmac_starts( &ctx
, key
, keylen
);
380 md5_hmac_update( &ctx
, input
, ilen
);
381 md5_hmac_finish( &ctx
, output
);
383 memset( &ctx
, 0, sizeof( md5_context
) );
386 #if defined(XYSSL_SELF_TEST)
389 * RFC 1321 test vectors
391 static const char md5_test_str
[7][81] =
396 { "message digest" },
397 { "abcdefghijklmnopqrstuvwxyz" },
398 { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
399 { "12345678901234567890123456789012345678901234567890123456789012" \
400 "345678901234567890" }
403 static const unsigned char md5_test_sum
[7][16] =
405 { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
406 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E },
407 { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
408 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 },
409 { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
410 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 },
411 { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
412 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 },
413 { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
414 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B },
415 { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
416 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F },
417 { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
418 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A }
424 int md5_self_test( int verbose
)
427 unsigned char md5sum
[16];
429 for( i
= 0; i
< 7; i
++ )
432 printf( " MD5 test #%d: ", i
+ 1 );
434 md5( (unsigned char *) md5_test_str
[i
],
435 strlen( md5_test_str
[i
] ), md5sum
);
437 if( memcmp( md5sum
, md5_test_sum
[i
], 16 ) != 0 )
440 printf( "failed\n" );
446 printf( "passed\n" );