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