• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
47 /*
48  * 32-bit integer manipulation macros (little endian)
49  */
50 #ifndef GET_UINT32_LE
51 #define GET_UINT32_LE(n,b,i)                            \
52 {                                                       \
53     (n) = ( (uint32_t) (b)[(i)    ]       )             \
54         | ( (uint32_t) (b)[(i) + 1] <<  8 )             \
55         | ( (uint32_t) (b)[(i) + 2] << 16 )             \
56         | ( (uint32_t) (b)[(i) + 3] << 24 );            \
57 }
58 #endif
59 
60 #ifndef PUT_UINT32_LE
61 #define PUT_UINT32_LE(n,b,i)                                    \
62 {                                                               \
63     (b)[(i)    ] = (unsigned char) ( ( (n)       ) & 0xFF );    \
64     (b)[(i) + 1] = (unsigned char) ( ( (n) >>  8 ) & 0xFF );    \
65     (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF );    \
66     (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF );    \
67 }
68 #endif
69 
mbedtls_md4_init(mbedtls_md4_context * ctx)70 void mbedtls_md4_init( mbedtls_md4_context *ctx )
71 {
72     memset( ctx, 0, sizeof( mbedtls_md4_context ) );
73 }
74 
mbedtls_md4_free(mbedtls_md4_context * ctx)75 void mbedtls_md4_free( mbedtls_md4_context *ctx )
76 {
77     if( ctx == NULL )
78         return;
79 
80     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md4_context ) );
81 }
82 
mbedtls_md4_clone(mbedtls_md4_context * dst,const mbedtls_md4_context * src)83 void mbedtls_md4_clone( mbedtls_md4_context *dst,
84                         const mbedtls_md4_context *src )
85 {
86     *dst = *src;
87 }
88 
89 /*
90  * MD4 context setup
91  */
mbedtls_md4_starts(mbedtls_md4_context * ctx)92 int mbedtls_md4_starts( mbedtls_md4_context *ctx )
93 {
94     ctx->total[0] = 0;
95     ctx->total[1] = 0;
96 
97     ctx->state[0] = 0x67452301;
98     ctx->state[1] = 0xEFCDAB89;
99     ctx->state[2] = 0x98BADCFE;
100     ctx->state[3] = 0x10325476;
101 
102     return( 0 );
103 }
104 
105 #if !defined(MBEDTLS_MD4_PROCESS_ALT)
mbedtls_internal_md4_process(mbedtls_md4_context * ctx,const unsigned char data[64])106 int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
107                                   const unsigned char data[64] )
108 {
109     struct
110     {
111         uint32_t X[16], A, B, C, D;
112     } local;
113 
114     GET_UINT32_LE( local.X[ 0], data,  0 );
115     GET_UINT32_LE( local.X[ 1], data,  4 );
116     GET_UINT32_LE( local.X[ 2], data,  8 );
117     GET_UINT32_LE( local.X[ 3], data, 12 );
118     GET_UINT32_LE( local.X[ 4], data, 16 );
119     GET_UINT32_LE( local.X[ 5], data, 20 );
120     GET_UINT32_LE( local.X[ 6], data, 24 );
121     GET_UINT32_LE( local.X[ 7], data, 28 );
122     GET_UINT32_LE( local.X[ 8], data, 32 );
123     GET_UINT32_LE( local.X[ 9], data, 36 );
124     GET_UINT32_LE( local.X[10], data, 40 );
125     GET_UINT32_LE( local.X[11], data, 44 );
126     GET_UINT32_LE( local.X[12], data, 48 );
127     GET_UINT32_LE( local.X[13], data, 52 );
128     GET_UINT32_LE( local.X[14], data, 56 );
129     GET_UINT32_LE( local.X[15], data, 60 );
130 
131 #define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
132 
133     local.A = ctx->state[0];
134     local.B = ctx->state[1];
135     local.C = ctx->state[2];
136     local.D = ctx->state[3];
137 
138 #define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
139 #define P(a,b,c,d,x,s)                           \
140     do                                           \
141     {                                            \
142         (a) += F((b),(c),(d)) + (x);             \
143         (a) = S((a),(s));                        \
144     } while( 0 )
145 
146 
147     P( local.A, local.B, local.C, local.D, local.X[ 0],  3 );
148     P( local.D, local.A, local.B, local.C, local.X[ 1],  7 );
149     P( local.C, local.D, local.A, local.B, local.X[ 2], 11 );
150     P( local.B, local.C, local.D, local.A, local.X[ 3], 19 );
151     P( local.A, local.B, local.C, local.D, local.X[ 4],  3 );
152     P( local.D, local.A, local.B, local.C, local.X[ 5],  7 );
153     P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
154     P( local.B, local.C, local.D, local.A, local.X[ 7], 19 );
155     P( local.A, local.B, local.C, local.D, local.X[ 8],  3 );
156     P( local.D, local.A, local.B, local.C, local.X[ 9],  7 );
157     P( local.C, local.D, local.A, local.B, local.X[10], 11 );
158     P( local.B, local.C, local.D, local.A, local.X[11], 19 );
159     P( local.A, local.B, local.C, local.D, local.X[12],  3 );
160     P( local.D, local.A, local.B, local.C, local.X[13],  7 );
161     P( local.C, local.D, local.A, local.B, local.X[14], 11 );
162     P( local.B, local.C, local.D, local.A, local.X[15], 19 );
163 
164 #undef P
165 #undef F
166 
167 #define F(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
168 #define P(a,b,c,d,x,s)                          \
169     do                                          \
170     {                                           \
171         (a) += F((b),(c),(d)) + (x) + 0x5A827999;       \
172         (a) = S((a),(s));                               \
173     } while( 0 )
174 
175     P( local.A, local.B, local.C, local.D, local.X[ 0],  3 );
176     P( local.D, local.A, local.B, local.C, local.X[ 4],  5 );
177     P( local.C, local.D, local.A, local.B, local.X[ 8],  9 );
178     P( local.B, local.C, local.D, local.A, local.X[12], 13 );
179     P( local.A, local.B, local.C, local.D, local.X[ 1],  3 );
180     P( local.D, local.A, local.B, local.C, local.X[ 5],  5 );
181     P( local.C, local.D, local.A, local.B, local.X[ 9],  9 );
182     P( local.B, local.C, local.D, local.A, local.X[13], 13 );
183     P( local.A, local.B, local.C, local.D, local.X[ 2],  3 );
184     P( local.D, local.A, local.B, local.C, local.X[ 6],  5 );
185     P( local.C, local.D, local.A, local.B, local.X[10],  9 );
186     P( local.B, local.C, local.D, local.A, local.X[14], 13 );
187     P( local.A, local.B, local.C, local.D, local.X[ 3],  3 );
188     P( local.D, local.A, local.B, local.C, local.X[ 7],  5 );
189     P( local.C, local.D, local.A, local.B, local.X[11],  9 );
190     P( local.B, local.C, local.D, local.A, local.X[15], 13 );
191 
192 #undef P
193 #undef F
194 
195 #define F(x,y,z) ((x) ^ (y) ^ (z))
196 #define P(a,b,c,d,x,s)                                  \
197     do                                                  \
198     {                                                   \
199         (a) += F((b),(c),(d)) + (x) + 0x6ED9EBA1;       \
200         (a) = S((a),(s));                               \
201     } while( 0 )
202 
203     P( local.A, local.B, local.C, local.D, local.X[ 0],  3 );
204     P( local.D, local.A, local.B, local.C, local.X[ 8],  9 );
205     P( local.C, local.D, local.A, local.B, local.X[ 4], 11 );
206     P( local.B, local.C, local.D, local.A, local.X[12], 15 );
207     P( local.A, local.B, local.C, local.D, local.X[ 2],  3 );
208     P( local.D, local.A, local.B, local.C, local.X[10],  9 );
209     P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
210     P( local.B, local.C, local.D, local.A, local.X[14], 15 );
211     P( local.A, local.B, local.C, local.D, local.X[ 1],  3 );
212     P( local.D, local.A, local.B, local.C, local.X[ 9],  9 );
213     P( local.C, local.D, local.A, local.B, local.X[ 5], 11 );
214     P( local.B, local.C, local.D, local.A, local.X[13], 15 );
215     P( local.A, local.B, local.C, local.D, local.X[ 3],  3 );
216     P( local.D, local.A, local.B, local.C, local.X[11],  9 );
217     P( local.C, local.D, local.A, local.B, local.X[ 7], 11 );
218     P( local.B, local.C, local.D, local.A, local.X[15], 15 );
219 
220 #undef F
221 #undef P
222 
223     ctx->state[0] += local.A;
224     ctx->state[1] += local.B;
225     ctx->state[2] += local.C;
226     ctx->state[3] += local.D;
227 
228     /* Zeroise variables to clear sensitive data from memory. */
229     mbedtls_platform_zeroize( &local, sizeof( local ) );
230 
231     return( 0 );
232 }
233 
234 #endif /* !MBEDTLS_MD4_PROCESS_ALT */
235 
236 /*
237  * MD4 process buffer
238  */
mbedtls_md4_update(mbedtls_md4_context * ctx,const unsigned char * input,size_t ilen)239 int mbedtls_md4_update( mbedtls_md4_context *ctx,
240                             const unsigned char *input,
241                             size_t ilen )
242 {
243     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
244     size_t fill;
245     uint32_t left;
246 
247     if( ilen == 0 )
248         return( 0 );
249 
250     left = ctx->total[0] & 0x3F;
251     fill = 64 - left;
252 
253     ctx->total[0] += (uint32_t) ilen;
254     ctx->total[0] &= 0xFFFFFFFF;
255 
256     if( ctx->total[0] < (uint32_t) ilen )
257         ctx->total[1]++;
258 
259     if( left && ilen >= fill )
260     {
261         memcpy( (void *) (ctx->buffer + left),
262                 (void *) input, fill );
263 
264         if( ( ret = mbedtls_internal_md4_process( ctx, ctx->buffer ) ) != 0 )
265             return( ret );
266 
267         input += fill;
268         ilen  -= fill;
269         left = 0;
270     }
271 
272     while( ilen >= 64 )
273     {
274         if( ( ret = mbedtls_internal_md4_process( ctx, input ) ) != 0 )
275             return( ret );
276 
277         input += 64;
278         ilen  -= 64;
279     }
280 
281     if( ilen > 0 )
282     {
283         memcpy( (void *) (ctx->buffer + left),
284                 (void *) input, ilen );
285     }
286 
287     return( 0 );
288 }
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(mbedtls_md4_context * ctx,unsigned char output[16])301 int mbedtls_md4_finish( 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     PUT_UINT32_LE( low,  msglen, 0 );
314     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( ctx, (unsigned char *)md4_padding, padn );
320     if( ret != 0 )
321         return( ret );
322 
323     if( ( ret = mbedtls_md4_update( ctx, msglen, 8 ) ) != 0 )
324         return( ret );
325 
326 
327     PUT_UINT32_LE( ctx->state[0], output,  0 );
328     PUT_UINT32_LE( ctx->state[1], output,  4 );
329     PUT_UINT32_LE( ctx->state[2], output,  8 );
330     PUT_UINT32_LE( ctx->state[3], output, 12 );
331 
332     return( 0 );
333 }
334 
335 #endif /* !MBEDTLS_MD4_ALT */
336 
337 /*
338  * output = MD4( input buffer )
339  */
mbedtls_md4(const unsigned char * input,size_t ilen,unsigned char output[16])340 int mbedtls_md4( const unsigned char *input,
341                      size_t ilen,
342                      unsigned char output[16] )
343 {
344     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
345     mbedtls_md4_context ctx;
346 
347     mbedtls_md4_init( &ctx );
348 
349     if( ( ret = mbedtls_md4_starts( &ctx ) ) != 0 )
350         goto exit;
351 
352     if( ( ret = mbedtls_md4_update( &ctx, input, ilen ) ) != 0 )
353         goto exit;
354 
355     if( ( ret = mbedtls_md4_finish( &ctx, output ) ) != 0 )
356         goto exit;
357 
358 exit:
359     mbedtls_md4_free( &ctx );
360 
361     return( ret );
362 }
363 
364 #if defined(MBEDTLS_SELF_TEST)
365 
366 /*
367  * RFC 1320 test vectors
368  */
369 static const unsigned char md4_test_str[7][81] =
370 {
371     { "" },
372     { "a" },
373     { "abc" },
374     { "message digest" },
375     { "abcdefghijklmnopqrstuvwxyz" },
376     { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" },
377     { "12345678901234567890123456789012345678901234567890123456789012345678901234567890" }
378 };
379 
380 static const size_t md4_test_strlen[7] =
381 {
382     0, 1, 3, 14, 26, 62, 80
383 };
384 
385 static const unsigned char md4_test_sum[7][16] =
386 {
387     { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31,
388       0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 },
389     { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46,
390       0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 },
391     { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52,
392       0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D },
393     { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8,
394       0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B },
395     { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD,
396       0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 },
397     { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35,
398       0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 },
399     { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19,
400       0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 }
401 };
402 
403 /*
404  * Checkup routine
405  */
mbedtls_md4_self_test(int verbose)406 int mbedtls_md4_self_test( int verbose )
407 {
408     int i, ret = 0;
409     unsigned char md4sum[16];
410 
411     for( i = 0; i < 7; i++ )
412     {
413         if( verbose != 0 )
414             mbedtls_printf( "  MD4 test #%d: ", i + 1 );
415 
416         ret = mbedtls_md4( md4_test_str[i], md4_test_strlen[i], md4sum );
417         if( ret != 0 )
418             goto fail;
419 
420         if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 )
421         {
422             ret = 1;
423             goto fail;
424         }
425 
426         if( verbose != 0 )
427             mbedtls_printf( "passed\n" );
428     }
429 
430     if( verbose != 0 )
431         mbedtls_printf( "\n" );
432 
433     return( 0 );
434 
435 fail:
436     if( verbose != 0 )
437         mbedtls_printf( "failed\n" );
438 
439     return( ret );
440 }
441 
442 #endif /* MBEDTLS_SELF_TEST */
443 
444 #endif /* MBEDTLS_MD4_C */