1 /*
2 * RFC 1186/1320 compliant MD4 implementation
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19 /*
20 * The MD4 algorithm was designed by Ron Rivest in 1990.
21 *
22 * http://www.ietf.org/rfc/rfc1186.txt
23 * http://www.ietf.org/rfc/rfc1320.txt
24 */
25
26 #include "common.h"
27
28 #if defined(MBEDTLS_MD4_C)
29
30 #include "mbedtls/md4.h"
31 #include "mbedtls/platform_util.h"
32 #include "mbedtls/error.h"
33
34 #include <string.h>
35
36 #if defined(MBEDTLS_SELF_TEST)
37 #if defined(MBEDTLS_PLATFORM_C)
38 #include "mbedtls/platform.h"
39 #else
40 #include <stdio.h>
41 #define mbedtls_printf printf
42 #endif /* MBEDTLS_PLATFORM_C */
43 #endif /* MBEDTLS_SELF_TEST */
44
45 #if !defined(MBEDTLS_MD4_ALT)
46
mbedtls_md4_init(mbedtls_md4_context * ctx)47 void mbedtls_md4_init( mbedtls_md4_context *ctx )
48 {
49 memset( ctx, 0, sizeof( mbedtls_md4_context ) );
50 }
51
mbedtls_md4_free(mbedtls_md4_context * ctx)52 void mbedtls_md4_free( mbedtls_md4_context *ctx )
53 {
54 if( ctx == NULL )
55 return;
56
57 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md4_context ) );
58 }
59
mbedtls_md4_clone(mbedtls_md4_context * dst,const mbedtls_md4_context * src)60 void mbedtls_md4_clone( mbedtls_md4_context *dst,
61 const mbedtls_md4_context *src )
62 {
63 *dst = *src;
64 }
65
66 /*
67 * MD4 context setup
68 */
mbedtls_md4_starts_ret(mbedtls_md4_context * ctx)69 int mbedtls_md4_starts_ret( mbedtls_md4_context *ctx )
70 {
71 ctx->total[0] = 0;
72 ctx->total[1] = 0;
73
74 ctx->state[0] = 0x67452301;
75 ctx->state[1] = 0xEFCDAB89;
76 ctx->state[2] = 0x98BADCFE;
77 ctx->state[3] = 0x10325476;
78
79 return( 0 );
80 }
81
82 #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_md4_starts(mbedtls_md4_context * ctx)83 void mbedtls_md4_starts( mbedtls_md4_context *ctx )
84 {
85 mbedtls_md4_starts_ret( ctx );
86 }
87 #endif
88
89 #if !defined(MBEDTLS_MD4_PROCESS_ALT)
mbedtls_internal_md4_process(mbedtls_md4_context * ctx,const unsigned char data[64])90 int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
91 const unsigned char data[64] )
92 {
93 struct
94 {
95 uint32_t X[16], A, B, C, D;
96 } local;
97
98 local.X[ 0] = MBEDTLS_GET_UINT32_LE( data, 0 );
99 local.X[ 1] = MBEDTLS_GET_UINT32_LE( data, 4 );
100 local.X[ 2] = MBEDTLS_GET_UINT32_LE( data, 8 );
101 local.X[ 3] = MBEDTLS_GET_UINT32_LE( data, 12 );
102 local.X[ 4] = MBEDTLS_GET_UINT32_LE( data, 16 );
103 local.X[ 5] = MBEDTLS_GET_UINT32_LE( data, 20 );
104 local.X[ 6] = MBEDTLS_GET_UINT32_LE( data, 24 );
105 local.X[ 7] = MBEDTLS_GET_UINT32_LE( data, 28 );
106 local.X[ 8] = MBEDTLS_GET_UINT32_LE( data, 32 );
107 local.X[ 9] = MBEDTLS_GET_UINT32_LE( data, 36 );
108 local.X[10] = MBEDTLS_GET_UINT32_LE( data, 40 );
109 local.X[11] = MBEDTLS_GET_UINT32_LE( data, 44 );
110 local.X[12] = MBEDTLS_GET_UINT32_LE( data, 48 );
111 local.X[13] = MBEDTLS_GET_UINT32_LE( data, 52 );
112 local.X[14] = MBEDTLS_GET_UINT32_LE( data, 56 );
113 local.X[15] = MBEDTLS_GET_UINT32_LE( data, 60 );
114
115 #define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
116
117 local.A = ctx->state[0];
118 local.B = ctx->state[1];
119 local.C = ctx->state[2];
120 local.D = ctx->state[3];
121
122 #define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
123 #define P(a,b,c,d,x,s) \
124 do \
125 { \
126 (a) += F((b),(c),(d)) + (x); \
127 (a) = S((a),(s)); \
128 } while( 0 )
129
130
131 P( local.A, local.B, local.C, local.D, local.X[ 0], 3 );
132 P( local.D, local.A, local.B, local.C, local.X[ 1], 7 );
133 P( local.C, local.D, local.A, local.B, local.X[ 2], 11 );
134 P( local.B, local.C, local.D, local.A, local.X[ 3], 19 );
135 P( local.A, local.B, local.C, local.D, local.X[ 4], 3 );
136 P( local.D, local.A, local.B, local.C, local.X[ 5], 7 );
137 P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
138 P( local.B, local.C, local.D, local.A, local.X[ 7], 19 );
139 P( local.A, local.B, local.C, local.D, local.X[ 8], 3 );
140 P( local.D, local.A, local.B, local.C, local.X[ 9], 7 );
141 P( local.C, local.D, local.A, local.B, local.X[10], 11 );
142 P( local.B, local.C, local.D, local.A, local.X[11], 19 );
143 P( local.A, local.B, local.C, local.D, local.X[12], 3 );
144 P( local.D, local.A, local.B, local.C, local.X[13], 7 );
145 P( local.C, local.D, local.A, local.B, local.X[14], 11 );
146 P( local.B, local.C, local.D, local.A, local.X[15], 19 );
147
148 #undef P
149 #undef F
150
151 #define F(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
152 #define P(a,b,c,d,x,s) \
153 do \
154 { \
155 (a) += F((b),(c),(d)) + (x) + 0x5A827999; \
156 (a) = S((a),(s)); \
157 } while( 0 )
158
159 P( local.A, local.B, local.C, local.D, local.X[ 0], 3 );
160 P( local.D, local.A, local.B, local.C, local.X[ 4], 5 );
161 P( local.C, local.D, local.A, local.B, local.X[ 8], 9 );
162 P( local.B, local.C, local.D, local.A, local.X[12], 13 );
163 P( local.A, local.B, local.C, local.D, local.X[ 1], 3 );
164 P( local.D, local.A, local.B, local.C, local.X[ 5], 5 );
165 P( local.C, local.D, local.A, local.B, local.X[ 9], 9 );
166 P( local.B, local.C, local.D, local.A, local.X[13], 13 );
167 P( local.A, local.B, local.C, local.D, local.X[ 2], 3 );
168 P( local.D, local.A, local.B, local.C, local.X[ 6], 5 );
169 P( local.C, local.D, local.A, local.B, local.X[10], 9 );
170 P( local.B, local.C, local.D, local.A, local.X[14], 13 );
171 P( local.A, local.B, local.C, local.D, local.X[ 3], 3 );
172 P( local.D, local.A, local.B, local.C, local.X[ 7], 5 );
173 P( local.C, local.D, local.A, local.B, local.X[11], 9 );
174 P( local.B, local.C, local.D, local.A, local.X[15], 13 );
175
176 #undef P
177 #undef F
178
179 #define F(x,y,z) ((x) ^ (y) ^ (z))
180 #define P(a,b,c,d,x,s) \
181 do \
182 { \
183 (a) += F((b),(c),(d)) + (x) + 0x6ED9EBA1; \
184 (a) = S((a),(s)); \
185 } while( 0 )
186
187 P( local.A, local.B, local.C, local.D, local.X[ 0], 3 );
188 P( local.D, local.A, local.B, local.C, local.X[ 8], 9 );
189 P( local.C, local.D, local.A, local.B, local.X[ 4], 11 );
190 P( local.B, local.C, local.D, local.A, local.X[12], 15 );
191 P( local.A, local.B, local.C, local.D, local.X[ 2], 3 );
192 P( local.D, local.A, local.B, local.C, local.X[10], 9 );
193 P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
194 P( local.B, local.C, local.D, local.A, local.X[14], 15 );
195 P( local.A, local.B, local.C, local.D, local.X[ 1], 3 );
196 P( local.D, local.A, local.B, local.C, local.X[ 9], 9 );
197 P( local.C, local.D, local.A, local.B, local.X[ 5], 11 );
198 P( local.B, local.C, local.D, local.A, local.X[13], 15 );
199 P( local.A, local.B, local.C, local.D, local.X[ 3], 3 );
200 P( local.D, local.A, local.B, local.C, local.X[11], 9 );
201 P( local.C, local.D, local.A, local.B, local.X[ 7], 11 );
202 P( local.B, local.C, local.D, local.A, local.X[15], 15 );
203
204 #undef F
205 #undef P
206
207 ctx->state[0] += local.A;
208 ctx->state[1] += local.B;
209 ctx->state[2] += local.C;
210 ctx->state[3] += local.D;
211
212 /* Zeroise variables to clear sensitive data from memory. */
213 mbedtls_platform_zeroize( &local, sizeof( local ) );
214
215 return( 0 );
216 }
217
218 #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_md4_process(mbedtls_md4_context * ctx,const unsigned char data[64])219 void mbedtls_md4_process( mbedtls_md4_context *ctx,
220 const unsigned char data[64] )
221 {
222 mbedtls_internal_md4_process( ctx, data );
223 }
224 #endif
225 #endif /* !MBEDTLS_MD4_PROCESS_ALT */
226
227 /*
228 * MD4 process buffer
229 */
mbedtls_md4_update_ret(mbedtls_md4_context * ctx,const unsigned char * input,size_t ilen)230 int mbedtls_md4_update_ret( mbedtls_md4_context *ctx,
231 const unsigned char *input,
232 size_t ilen )
233 {
234 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
235 size_t fill;
236 uint32_t left;
237
238 if( ilen == 0 )
239 return( 0 );
240
241 left = ctx->total[0] & 0x3F;
242 fill = 64 - left;
243
244 ctx->total[0] += (uint32_t) ilen;
245 ctx->total[0] &= 0xFFFFFFFF;
246
247 if( ctx->total[0] < (uint32_t) ilen )
248 ctx->total[1]++;
249
250 if( left && ilen >= fill )
251 {
252 memcpy( (void *) (ctx->buffer + left),
253 (void *) input, fill );
254
255 if( ( ret = mbedtls_internal_md4_process( ctx, ctx->buffer ) ) != 0 )
256 return( ret );
257
258 input += fill;
259 ilen -= fill;
260 left = 0;
261 }
262
263 while( ilen >= 64 )
264 {
265 if( ( ret = mbedtls_internal_md4_process( ctx, input ) ) != 0 )
266 return( ret );
267
268 input += 64;
269 ilen -= 64;
270 }
271
272 if( ilen > 0 )
273 {
274 memcpy( (void *) (ctx->buffer + left),
275 (void *) input, ilen );
276 }
277
278 return( 0 );
279 }
280
281 #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_md4_update(mbedtls_md4_context * ctx,const unsigned char * input,size_t ilen)282 void mbedtls_md4_update( mbedtls_md4_context *ctx,
283 const unsigned char *input,
284 size_t ilen )
285 {
286 mbedtls_md4_update_ret( ctx, input, ilen );
287 }
288 #endif
289
290 static const unsigned char md4_padding[64] =
291 {
292 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
296 };
297
298 /*
299 * MD4 final digest
300 */
mbedtls_md4_finish_ret(mbedtls_md4_context * ctx,unsigned char output[16])301 int mbedtls_md4_finish_ret( mbedtls_md4_context *ctx,
302 unsigned char output[16] )
303 {
304 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
305 uint32_t last, padn;
306 uint32_t high, low;
307 unsigned char msglen[8];
308
309 high = ( ctx->total[0] >> 29 )
310 | ( ctx->total[1] << 3 );
311 low = ( ctx->total[0] << 3 );
312
313 MBEDTLS_PUT_UINT32_LE( low, msglen, 0 );
314 MBEDTLS_PUT_UINT32_LE( high, msglen, 4 );
315
316 last = ctx->total[0] & 0x3F;
317 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
318
319 ret = mbedtls_md4_update_ret( ctx, (unsigned char *)md4_padding, padn );
320 if( ret != 0 )
321 return( ret );
322
323 if( ( ret = mbedtls_md4_update_ret( ctx, msglen, 8 ) ) != 0 )
324 return( ret );
325
326
327 MBEDTLS_PUT_UINT32_LE( ctx->state[0], output, 0 );
328 MBEDTLS_PUT_UINT32_LE( ctx->state[1], output, 4 );
329 MBEDTLS_PUT_UINT32_LE( ctx->state[2], output, 8 );
330 MBEDTLS_PUT_UINT32_LE( ctx->state[3], output, 12 );
331
332 return( 0 );
333 }
334
335 #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_md4_finish(mbedtls_md4_context * ctx,unsigned char output[16])336 void mbedtls_md4_finish( mbedtls_md4_context *ctx,
337 unsigned char output[16] )
338 {
339 mbedtls_md4_finish_ret( ctx, output );
340 }
341 #endif
342
343 #endif /* !MBEDTLS_MD4_ALT */
344
345 /*
346 * output = MD4( input buffer )
347 */
mbedtls_md4_ret(const unsigned char * input,size_t ilen,unsigned char output[16])348 int mbedtls_md4_ret( const unsigned char *input,
349 size_t ilen,
350 unsigned char output[16] )
351 {
352 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
353 mbedtls_md4_context ctx;
354
355 mbedtls_md4_init( &ctx );
356
357 if( ( ret = mbedtls_md4_starts_ret( &ctx ) ) != 0 )
358 goto exit;
359
360 if( ( ret = mbedtls_md4_update_ret( &ctx, input, ilen ) ) != 0 )
361 goto exit;
362
363 if( ( ret = mbedtls_md4_finish_ret( &ctx, output ) ) != 0 )
364 goto exit;
365
366 exit:
367 mbedtls_md4_free( &ctx );
368
369 return( ret );
370 }
371
372 #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_md4(const unsigned char * input,size_t ilen,unsigned char output[16])373 void mbedtls_md4( const unsigned char *input,
374 size_t ilen,
375 unsigned char output[16] )
376 {
377 mbedtls_md4_ret( input, ilen, output );
378 }
379 #endif
380
381 #if defined(MBEDTLS_SELF_TEST)
382
383 /*
384 * RFC 1320 test vectors
385 */
386 static const unsigned char md4_test_str[7][81] =
387 {
388 { "" },
389 { "a" },
390 { "abc" },
391 { "message digest" },
392 { "abcdefghijklmnopqrstuvwxyz" },
393 { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
394 { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }
395 };
396
397 static const size_t md4_test_strlen[7] =
398 {
399 0, 1, 3, 14, 26, 62, 80
400 };
401
402 static const unsigned char md4_test_sum[7][16] =
403 {
404 { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31,
405 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 },
406 { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46,
407 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 },
408 { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52,
409 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D },
410 { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8,
411 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B },
412 { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD,
413 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 },
414 { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35,
415 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 },
416 { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19,
417 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 }
418 };
419
420 /*
421 * Checkup routine
422 */
mbedtls_md4_self_test(int verbose)423 int mbedtls_md4_self_test( int verbose )
424 {
425 int i, ret = 0;
426 unsigned char md4sum[16];
427
428 for( i = 0; i < 7; i++ )
429 {
430 if( verbose != 0 )
431 mbedtls_printf( " MD4 test #%d: ", i + 1 );
432
433 ret = mbedtls_md4_ret( md4_test_str[i], md4_test_strlen[i], md4sum );
434 if( ret != 0 )
435 goto fail;
436
437 if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 )
438 {
439 ret = 1;
440 goto fail;
441 }
442
443 if( verbose != 0 )
444 mbedtls_printf( "passed\n" );
445 }
446
447 if( verbose != 0 )
448 mbedtls_printf( "\n" );
449
450 return( 0 );
451
452 fail:
453 if( verbose != 0 )
454 mbedtls_printf( "failed\n" );
455
456 return( ret );
457 }
458
459 #endif /* MBEDTLS_SELF_TEST */
460
461 #endif /* MBEDTLS_MD4_C */
462