1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#if !defined(CURL_DISABLE_CRYPTO_AUTH)
28
29#include "curl_md4.h"
30#include "warnless.h"
31
32
33#ifdef USE_OPENSSL
34#include <openssl/opensslconf.h>
35#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) && \
36 !defined(USE_AMISSL)
37/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */
38#define OPENSSL_NO_MD4
39#endif
40#endif /* USE_OPENSSL */
41
42#ifdef USE_WOLFSSL
43#include <wolfssl/options.h>
44#ifdef NO_MD4
45#define WOLFSSL_NO_MD4
46#endif
47#endif
48
49#ifdef USE_MBEDTLS
50#include <mbedtls/version.h>
51#if MBEDTLS_VERSION_NUMBER >= 0x03000000
52#include <mbedtls/mbedtls_config.h>
53#else
54#include <mbedtls/config.h>
55#endif
56
57#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
58 #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
59#endif
60#endif /* USE_MBEDTLS */
61
62#if defined(USE_GNUTLS)
63
64#include <nettle/md4.h>
65
66#include "curl_memory.h"
67
68/* The last #include file should be: */
69#include "memdebug.h"
70
71typedef struct md4_ctx MD4_CTX;
72
73static void MD4_Init(MD4_CTX *ctx)
74{
75 md4_init(ctx);
76}
77
78static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
79{
80 md4_update(ctx, size, data);
81}
82
83static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
84{
85 md4_digest(ctx, MD4_DIGEST_SIZE, result);
86}
87
88/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */
89#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
90#include <wolfssl/openssl/md4.h>
91
92#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
93#include <openssl/md4.h>
94
95#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
96 (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
97 defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
98 (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
99 (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
100 (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
101
102#include <CommonCrypto/CommonDigest.h>
103
104#include "curl_memory.h"
105
106/* The last #include file should be: */
107#include "memdebug.h"
108
109typedef CC_MD4_CTX MD4_CTX;
110
111static void MD4_Init(MD4_CTX *ctx)
112{
113 (void)CC_MD4_Init(ctx);
114}
115
116static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
117{
118 (void)CC_MD4_Update(ctx, data, (CC_LONG)size);
119}
120
121static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
122{
123 (void)CC_MD4_Final(result, ctx);
124}
125
126#elif defined(USE_WIN32_CRYPTO)
127
128#include <wincrypt.h>
129
130#include "curl_memory.h"
131
132/* The last #include file should be: */
133#include "memdebug.h"
134
135struct md4_ctx {
136 HCRYPTPROV hCryptProv;
137 HCRYPTHASH hHash;
138};
139typedef struct md4_ctx MD4_CTX;
140
141static void MD4_Init(MD4_CTX *ctx)
142{
143 ctx->hCryptProv = 0;
144 ctx->hHash = 0;
145
146 if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
147 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
148 CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash);
149 }
150}
151
152static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
153{
154 CryptHashData(ctx->hHash, (BYTE *)data, (unsigned int) size, 0);
155}
156
157static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
158{
159 unsigned long length = 0;
160
161 CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
162 if(length == MD4_DIGEST_LENGTH)
163 CryptGetHashParam(ctx->hHash, HP_HASHVAL, result, &length, 0);
164
165 if(ctx->hHash)
166 CryptDestroyHash(ctx->hHash);
167
168 if(ctx->hCryptProv)
169 CryptReleaseContext(ctx->hCryptProv, 0);
170}
171
172#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C))
173
174#include <mbedtls/md4.h>
175
176#include "curl_memory.h"
177
178/* The last #include file should be: */
179#include "memdebug.h"
180
181struct md4_ctx {
182 void *data;
183 unsigned long size;
184};
185typedef struct md4_ctx MD4_CTX;
186
187static void MD4_Init(MD4_CTX *ctx)
188{
189 ctx->data = NULL;
190 ctx->size = 0;
191}
192
193static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
194{
195 if(!ctx->data) {
196 ctx->data = malloc(size);
197 if(ctx->data) {
198 memcpy(ctx->data, data, size);
199 ctx->size = size;
200 }
201 }
202}
203
204static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
205{
206 if(ctx->data) {
207#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
208 mbedtls_md4(ctx->data, ctx->size, result);
209#else
210 (void) mbedtls_md4_ret(ctx->data, ctx->size, result);
211#endif
212
213 Curl_safefree(ctx->data);
214 ctx->size = 0;
215 }
216}
217
218#else
219/* When no other crypto library is available, or the crypto library doesn't
220 * support MD4, we use this code segment this implementation of it
221 *
222 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
223 * MD4 Message-Digest Algorithm (RFC 1320).
224 *
225 * Homepage:
226 https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
227 *
228 * Author:
229 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
230 *
231 * This software was written by Alexander Peslyak in 2001. No copyright is
232 * claimed, and the software is hereby placed in the public domain. In case
233 * this attempt to disclaim copyright and place the software in the public
234 * domain is deemed null and void, then the software is Copyright (c) 2001
235 * Alexander Peslyak and it is hereby released to the general public under the
236 * following terms:
237 *
238 * Redistribution and use in source and binary forms, with or without
239 * modification, are permitted.
240 *
241 * There's ABSOLUTELY NO WARRANTY, express or implied.
242 *
243 * (This is a heavily cut-down "BSD license".)
244 *
245 * This differs from Colin Plumb's older public domain implementation in that
246 * no exactly 32-bit integer data type is required (any 32-bit or wider
247 * unsigned integer data type will do), there's no compile-time endianness
248 * configuration, and the function prototypes match OpenSSL's. No code from
249 * Colin Plumb's implementation has been reused; this comment merely compares
250 * the properties of the two independent implementations.
251 *
252 * The primary goals of this implementation are portability and ease of use.
253 * It is meant to be fast, but not as fast as possible. Some known
254 * optimizations are not included to reduce source code size and avoid
255 * compile-time configuration.
256 */
257
258
259#include <string.h>
260
261/* Any 32-bit or wider unsigned integer data type will do */
262typedef unsigned int MD4_u32plus;
263
264struct md4_ctx {
265 MD4_u32plus lo, hi;
266 MD4_u32plus a, b, c, d;
267 unsigned char buffer[64];
268 MD4_u32plus block[16];
269};
270typedef struct md4_ctx MD4_CTX;
271
272static void MD4_Init(MD4_CTX *ctx);
273static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size);
274static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
275
276/*
277 * The basic MD4 functions.
278 *
279 * F and G are optimized compared to their RFC 1320 definitions, with the
280 * optimization for F borrowed from Colin Plumb's MD5 implementation.
281 */
282#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
283#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
284#define H(x, y, z) ((x) ^ (y) ^ (z))
285
286/*
287 * The MD4 transformation for all three rounds.
288 */
289#define STEP(f, a, b, c, d, x, s) \
290 (a) += f((b), (c), (d)) + (x); \
291 (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));
292
293/*
294 * SET reads 4 input bytes in little-endian byte order and stores them
295 * in a properly aligned word in host byte order.
296 *
297 * The check for little-endian architectures that tolerate unaligned
298 * memory accesses is just an optimization. Nothing will break if it
299 * doesn't work.
300 */
301#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
302#define SET(n) \
303 (*(MD4_u32plus *)(void *)&ptr[(n) * 4])
304#define GET(n) \
305 SET(n)
306#else
307#define SET(n) \
308 (ctx->block[(n)] = \
309 (MD4_u32plus)ptr[(n) * 4] | \
310 ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \
311 ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \
312 ((MD4_u32plus)ptr[(n) * 4 + 3] << 24))
313#define GET(n) \
314 (ctx->block[(n)])
315#endif
316
317/*
318 * This processes one or more 64-byte data blocks, but does NOT update
319 * the bit counters. There are no alignment requirements.
320 */
321static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
322{
323 const unsigned char *ptr;
324 MD4_u32plus a, b, c, d;
325
326 ptr = (const unsigned char *)data;
327
328 a = ctx->a;
329 b = ctx->b;
330 c = ctx->c;
331 d = ctx->d;
332
333 do {
334 MD4_u32plus saved_a, saved_b, saved_c, saved_d;
335
336 saved_a = a;
337 saved_b = b;
338 saved_c = c;
339 saved_d = d;
340
341/* Round 1 */
342 STEP(F, a, b, c, d, SET(0), 3)
343 STEP(F, d, a, b, c, SET(1), 7)
344 STEP(F, c, d, a, b, SET(2), 11)
345 STEP(F, b, c, d, a, SET(3), 19)
346 STEP(F, a, b, c, d, SET(4), 3)
347 STEP(F, d, a, b, c, SET(5), 7)
348 STEP(F, c, d, a, b, SET(6), 11)
349 STEP(F, b, c, d, a, SET(7), 19)
350 STEP(F, a, b, c, d, SET(8), 3)
351 STEP(F, d, a, b, c, SET(9), 7)
352 STEP(F, c, d, a, b, SET(10), 11)
353 STEP(F, b, c, d, a, SET(11), 19)
354 STEP(F, a, b, c, d, SET(12), 3)
355 STEP(F, d, a, b, c, SET(13), 7)
356 STEP(F, c, d, a, b, SET(14), 11)
357 STEP(F, b, c, d, a, SET(15), 19)
358
359/* Round 2 */
360 STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
361 STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
362 STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
363 STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
364 STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
365 STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
366 STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
367 STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
368 STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
369 STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
370 STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
371 STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
372 STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
373 STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
374 STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
375 STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)
376
377/* Round 3 */
378 STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
379 STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
380 STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
381 STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
382 STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
383 STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
384 STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
385 STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
386 STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
387 STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
388 STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
389 STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
390 STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
391 STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
392 STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
393 STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)
394
395 a += saved_a;
396 b += saved_b;
397 c += saved_c;
398 d += saved_d;
399
400 ptr += 64;
401 } while(size -= 64);
402
403 ctx->a = a;
404 ctx->b = b;
405 ctx->c = c;
406 ctx->d = d;
407
408 return ptr;
409}
410
411static void MD4_Init(MD4_CTX *ctx)
412{
413 ctx->a = 0x67452301;
414 ctx->b = 0xefcdab89;
415 ctx->c = 0x98badcfe;
416 ctx->d = 0x10325476;
417
418 ctx->lo = 0;
419 ctx->hi = 0;
420}
421
422static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
423{
424 MD4_u32plus saved_lo;
425 unsigned long used;
426
427 saved_lo = ctx->lo;
428 ctx->lo = (saved_lo + size) & 0x1fffffff;
429 if(ctx->lo < saved_lo)
430 ctx->hi++;
431 ctx->hi += (MD4_u32plus)size >> 29;
432
433 used = saved_lo & 0x3f;
434
435 if(used) {
436 unsigned long available = 64 - used;
437
438 if(size < available) {
439 memcpy(&ctx->buffer[used], data, size);
440 return;
441 }
442
443 memcpy(&ctx->buffer[used], data, available);
444 data = (const unsigned char *)data + available;
445 size -= available;
446 body(ctx, ctx->buffer, 64);
447 }
448
449 if(size >= 64) {
450 data = body(ctx, data, size & ~(unsigned long)0x3f);
451 size &= 0x3f;
452 }
453
454 memcpy(ctx->buffer, data, size);
455}
456
457static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
458{
459 unsigned long used, available;
460
461 used = ctx->lo & 0x3f;
462
463 ctx->buffer[used++] = 0x80;
464
465 available = 64 - used;
466
467 if(available < 8) {
468 memset(&ctx->buffer[used], 0, available);
469 body(ctx, ctx->buffer, 64);
470 used = 0;
471 available = 64;
472 }
473
474 memset(&ctx->buffer[used], 0, available - 8);
475
476 ctx->lo <<= 3;
477 ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
478 ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
479 ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
480 ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff);
481 ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
482 ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
483 ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
484 ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
485
486 body(ctx, ctx->buffer, 64);
487
488 result[0] = curlx_ultouc((ctx->a)&0xff);
489 result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
490 result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
491 result[3] = curlx_ultouc(ctx->a >> 24);
492 result[4] = curlx_ultouc((ctx->b)&0xff);
493 result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
494 result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
495 result[7] = curlx_ultouc(ctx->b >> 24);
496 result[8] = curlx_ultouc((ctx->c)&0xff);
497 result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
498 result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
499 result[11] = curlx_ultouc(ctx->c >> 24);
500 result[12] = curlx_ultouc((ctx->d)&0xff);
501 result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
502 result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
503 result[15] = curlx_ultouc(ctx->d >> 24);
504
505 memset(ctx, 0, sizeof(*ctx));
506}
507
508#endif /* CRYPTO LIBS */
509
510void Curl_md4it(unsigned char *output, const unsigned char *input,
511 const size_t len)
512{
513 MD4_CTX ctx;
514
515 MD4_Init(&ctx);
516 MD4_Update(&ctx, input, curlx_uztoui(len));
517 MD4_Final(output, &ctx);
518}
519
520#endif /* CURL_DISABLE_CRYPTO_AUTH */
521