blob: acf00cb71b2fb10af3d91258f5e50030622828de [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1186/1320 compliant MD4 implementation
3 *
Paul Bakkere0ccd0a2009-01-04 16:27:10 +00004 * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
5 *
Paul Bakker27db1f52009-01-25 15:27:00 +00006 * Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
Paul Bakker5121ce52009-01-03 21:22:43 +00007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22/*
23 * The MD4 algorithm was designed by Ron Rivest in 1990.
24 *
25 * http://www.ietf.org/rfc/rfc1186.txt
26 * http://www.ietf.org/rfc/rfc1320.txt
27 */
28
Paul Bakker40e46942009-01-03 21:51:57 +000029#include "polarssl/config.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000030
Paul Bakker40e46942009-01-03 21:51:57 +000031#if defined(POLARSSL_MD4_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000032
Paul Bakker40e46942009-01-03 21:51:57 +000033#include "polarssl/md4.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000034
35#include <string.h>
36#include <stdio.h>
37
38/*
39 * 32-bit integer manipulation macros (little endian)
40 */
41#ifndef GET_ULONG_LE
42#define GET_ULONG_LE(n,b,i) \
43{ \
44 (n) = ( (unsigned long) (b)[(i) ] ) \
45 | ( (unsigned long) (b)[(i) + 1] << 8 ) \
46 | ( (unsigned long) (b)[(i) + 2] << 16 ) \
47 | ( (unsigned long) (b)[(i) + 3] << 24 ); \
48}
49#endif
50
51#ifndef PUT_ULONG_LE
52#define PUT_ULONG_LE(n,b,i) \
53{ \
54 (b)[(i) ] = (unsigned char) ( (n) ); \
55 (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
56 (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
57 (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
58}
59#endif
60
61/*
62 * MD4 context setup
63 */
64void md4_starts( md4_context *ctx )
65{
66 ctx->total[0] = 0;
67 ctx->total[1] = 0;
68
69 ctx->state[0] = 0x67452301;
70 ctx->state[1] = 0xEFCDAB89;
71 ctx->state[2] = 0x98BADCFE;
72 ctx->state[3] = 0x10325476;
73}
74
75static void md4_process( md4_context *ctx, unsigned char data[64] )
76{
77 unsigned long X[16], A, B, C, D;
78
79 GET_ULONG_LE( X[ 0], data, 0 );
80 GET_ULONG_LE( X[ 1], data, 4 );
81 GET_ULONG_LE( X[ 2], data, 8 );
82 GET_ULONG_LE( X[ 3], data, 12 );
83 GET_ULONG_LE( X[ 4], data, 16 );
84 GET_ULONG_LE( X[ 5], data, 20 );
85 GET_ULONG_LE( X[ 6], data, 24 );
86 GET_ULONG_LE( X[ 7], data, 28 );
87 GET_ULONG_LE( X[ 8], data, 32 );
88 GET_ULONG_LE( X[ 9], data, 36 );
89 GET_ULONG_LE( X[10], data, 40 );
90 GET_ULONG_LE( X[11], data, 44 );
91 GET_ULONG_LE( X[12], data, 48 );
92 GET_ULONG_LE( X[13], data, 52 );
93 GET_ULONG_LE( X[14], data, 56 );
94 GET_ULONG_LE( X[15], data, 60 );
95
96#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
97
98 A = ctx->state[0];
99 B = ctx->state[1];
100 C = ctx->state[2];
101 D = ctx->state[3];
102
103#define F(x, y, z) ((x & y) | ((~x) & z))
104#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); }
105
106 P( A, B, C, D, X[ 0], 3 );
107 P( D, A, B, C, X[ 1], 7 );
108 P( C, D, A, B, X[ 2], 11 );
109 P( B, C, D, A, X[ 3], 19 );
110 P( A, B, C, D, X[ 4], 3 );
111 P( D, A, B, C, X[ 5], 7 );
112 P( C, D, A, B, X[ 6], 11 );
113 P( B, C, D, A, X[ 7], 19 );
114 P( A, B, C, D, X[ 8], 3 );
115 P( D, A, B, C, X[ 9], 7 );
116 P( C, D, A, B, X[10], 11 );
117 P( B, C, D, A, X[11], 19 );
118 P( A, B, C, D, X[12], 3 );
119 P( D, A, B, C, X[13], 7 );
120 P( C, D, A, B, X[14], 11 );
121 P( B, C, D, A, X[15], 19 );
122
123#undef P
124#undef F
125
126#define F(x,y,z) ((x & y) | (x & z) | (y & z))
127#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); }
128
129 P( A, B, C, D, X[ 0], 3 );
130 P( D, A, B, C, X[ 4], 5 );
131 P( C, D, A, B, X[ 8], 9 );
132 P( B, C, D, A, X[12], 13 );
133 P( A, B, C, D, X[ 1], 3 );
134 P( D, A, B, C, X[ 5], 5 );
135 P( C, D, A, B, X[ 9], 9 );
136 P( B, C, D, A, X[13], 13 );
137 P( A, B, C, D, X[ 2], 3 );
138 P( D, A, B, C, X[ 6], 5 );
139 P( C, D, A, B, X[10], 9 );
140 P( B, C, D, A, X[14], 13 );
141 P( A, B, C, D, X[ 3], 3 );
142 P( D, A, B, C, X[ 7], 5 );
143 P( C, D, A, B, X[11], 9 );
144 P( B, C, D, A, X[15], 13 );
145
146#undef P
147#undef F
148
149#define F(x,y,z) (x ^ y ^ z)
150#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); }
151
152 P( A, B, C, D, X[ 0], 3 );
153 P( D, A, B, C, X[ 8], 9 );
154 P( C, D, A, B, X[ 4], 11 );
155 P( B, C, D, A, X[12], 15 );
156 P( A, B, C, D, X[ 2], 3 );
157 P( D, A, B, C, X[10], 9 );
158 P( C, D, A, B, X[ 6], 11 );
159 P( B, C, D, A, X[14], 15 );
160 P( A, B, C, D, X[ 1], 3 );
161 P( D, A, B, C, X[ 9], 9 );
162 P( C, D, A, B, X[ 5], 11 );
163 P( B, C, D, A, X[13], 15 );
164 P( A, B, C, D, X[ 3], 3 );
165 P( D, A, B, C, X[11], 9 );
166 P( C, D, A, B, X[ 7], 11 );
167 P( B, C, D, A, X[15], 15 );
168
169#undef F
170#undef P
171
172 ctx->state[0] += A;
173 ctx->state[1] += B;
174 ctx->state[2] += C;
175 ctx->state[3] += D;
176}
177
178/*
179 * MD4 process buffer
180 */
181void md4_update( md4_context *ctx, unsigned char *input, int ilen )
182{
183 int fill;
184 unsigned long left;
185
186 if( ilen <= 0 )
187 return;
188
189 left = ctx->total[0] & 0x3F;
190 fill = 64 - left;
191
192 ctx->total[0] += ilen;
193 ctx->total[0] &= 0xFFFFFFFF;
194
195 if( ctx->total[0] < (unsigned long) ilen )
196 ctx->total[1]++;
197
198 if( left && ilen >= fill )
199 {
200 memcpy( (void *) (ctx->buffer + left),
201 (void *) input, fill );
202 md4_process( ctx, ctx->buffer );
203 input += fill;
204 ilen -= fill;
205 left = 0;
206 }
207
208 while( ilen >= 64 )
209 {
210 md4_process( ctx, input );
211 input += 64;
212 ilen -= 64;
213 }
214
215 if( ilen > 0 )
216 {
217 memcpy( (void *) (ctx->buffer + left),
218 (void *) input, ilen );
219 }
220}
221
222static const unsigned char md4_padding[64] =
223{
224 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
228};
229
230/*
231 * MD4 final digest
232 */
233void md4_finish( md4_context *ctx, unsigned char output[16] )
234{
235 unsigned long last, padn;
236 unsigned long high, low;
237 unsigned char msglen[8];
238
239 high = ( ctx->total[0] >> 29 )
240 | ( ctx->total[1] << 3 );
241 low = ( ctx->total[0] << 3 );
242
243 PUT_ULONG_LE( low, msglen, 0 );
244 PUT_ULONG_LE( high, msglen, 4 );
245
246 last = ctx->total[0] & 0x3F;
247 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
248
249 md4_update( ctx, (unsigned char *) md4_padding, padn );
250 md4_update( ctx, msglen, 8 );
251
252 PUT_ULONG_LE( ctx->state[0], output, 0 );
253 PUT_ULONG_LE( ctx->state[1], output, 4 );
254 PUT_ULONG_LE( ctx->state[2], output, 8 );
255 PUT_ULONG_LE( ctx->state[3], output, 12 );
256}
257
258/*
259 * output = MD4( input buffer )
260 */
261void md4( unsigned char *input, int ilen, unsigned char output[16] )
262{
263 md4_context ctx;
264
265 md4_starts( &ctx );
266 md4_update( &ctx, input, ilen );
267 md4_finish( &ctx, output );
268
269 memset( &ctx, 0, sizeof( md4_context ) );
270}
271
272/*
273 * output = MD4( file contents )
274 */
275int md4_file( char *path, unsigned char output[16] )
276{
277 FILE *f;
278 size_t n;
279 md4_context ctx;
280 unsigned char buf[1024];
281
282 if( ( f = fopen( path, "rb" ) ) == NULL )
283 return( 1 );
284
285 md4_starts( &ctx );
286
287 while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
288 md4_update( &ctx, buf, (int) n );
289
290 md4_finish( &ctx, output );
291
292 memset( &ctx, 0, sizeof( md4_context ) );
293
294 if( ferror( f ) != 0 )
295 {
296 fclose( f );
297 return( 2 );
298 }
299
300 fclose( f );
301 return( 0 );
302}
303
304/*
305 * MD4 HMAC context setup
306 */
307void md4_hmac_starts( md4_context *ctx, unsigned char *key, int keylen )
308{
309 int i;
310 unsigned char sum[16];
311
312 if( keylen > 64 )
313 {
314 md4( key, keylen, sum );
315 keylen = 16;
316 key = sum;
317 }
318
319 memset( ctx->ipad, 0x36, 64 );
320 memset( ctx->opad, 0x5C, 64 );
321
322 for( i = 0; i < keylen; i++ )
323 {
324 ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
325 ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
326 }
327
328 md4_starts( ctx );
329 md4_update( ctx, ctx->ipad, 64 );
330
331 memset( sum, 0, sizeof( sum ) );
332}
333
334/*
335 * MD4 HMAC process buffer
336 */
337void md4_hmac_update( md4_context *ctx, unsigned char *input, int ilen )
338{
339 md4_update( ctx, input, ilen );
340}
341
342/*
343 * MD4 HMAC final digest
344 */
345void md4_hmac_finish( md4_context *ctx, unsigned char output[16] )
346{
347 unsigned char tmpbuf[16];
348
349 md4_finish( ctx, tmpbuf );
350 md4_starts( ctx );
351 md4_update( ctx, ctx->opad, 64 );
352 md4_update( ctx, tmpbuf, 16 );
353 md4_finish( ctx, output );
354
355 memset( tmpbuf, 0, sizeof( tmpbuf ) );
356}
357
358/*
359 * output = HMAC-MD4( hmac key, input buffer )
360 */
361void md4_hmac( unsigned char *key, int keylen, unsigned char *input, int ilen,
362 unsigned char output[16] )
363{
364 md4_context ctx;
365
366 md4_hmac_starts( &ctx, key, keylen );
367 md4_hmac_update( &ctx, input, ilen );
368 md4_hmac_finish( &ctx, output );
369
370 memset( &ctx, 0, sizeof( md4_context ) );
371}
372
Paul Bakker40e46942009-01-03 21:51:57 +0000373#if defined(POLARSSL_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000374
375/*
376 * RFC 1320 test vectors
377 */
378static const char md4_test_str[7][81] =
379{
380 { "" },
381 { "a" },
382 { "abc" },
383 { "message digest" },
384 { "abcdefghijklmnopqrstuvwxyz" },
385 { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
386 { "12345678901234567890123456789012345678901234567890123456789012" \
387 "345678901234567890" }
388};
389
390static const unsigned char md4_test_sum[7][16] =
391{
392 { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31,
393 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 },
394 { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46,
395 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 },
396 { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52,
397 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D },
398 { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8,
399 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B },
400 { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD,
401 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 },
402 { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35,
403 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 },
404 { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19,
405 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 }
406};
407
408/*
409 * Checkup routine
410 */
411int md4_self_test( int verbose )
412{
413 int i;
414 unsigned char md4sum[16];
415
416 for( i = 0; i < 7; i++ )
417 {
418 if( verbose != 0 )
419 printf( " MD4 test #%d: ", i + 1 );
420
421 md4( (unsigned char *) md4_test_str[i],
422 strlen( md4_test_str[i] ), md4sum );
423
424 if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 )
425 {
426 if( verbose != 0 )
427 printf( "failed\n" );
428
429 return( 1 );
430 }
431
432 if( verbose != 0 )
433 printf( "passed\n" );
434 }
435
436 if( verbose != 0 )
437 printf( "\n" );
438
439 return( 0 );
440}
441
442#endif
443
444#endif