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