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