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