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