Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / md5.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, 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 #ifndef CURL_DISABLE_CRYPTO_AUTH
28
29 #include <curl/curl.h>
30
31 #include "curl_md5.h"
32 #include "curl_hmac.h"
33 #include "warnless.h"
34
35 #ifdef USE_MBEDTLS
36 #include <mbedtls/version.h>
37
38 #if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
39    (MBEDTLS_VERSION_NUMBER < 0x03000000)
40   #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
41 #endif
42 #endif /* USE_MBEDTLS */
43
44 #ifdef USE_OPENSSL
45   #include <openssl/opensslconf.h>
46   #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0)
47     #define USE_OPENSSL_MD5
48   #endif
49 #endif
50
51 #ifdef USE_WOLFSSL
52   #include <wolfssl/options.h>
53   #ifndef NO_MD5
54     #define USE_WOLFSSL_MD5
55   #endif
56 #endif
57
58 #if defined(USE_GNUTLS)
59
60 #include <nettle/md5.h>
61 #include "curl_memory.h"
62 /* The last #include file should be: */
63 #include "memdebug.h"
64
65 typedef struct md5_ctx my_md5_ctx;
66
67 static CURLcode my_md5_init(my_md5_ctx *ctx)
68 {
69   md5_init(ctx);
70   return CURLE_OK;
71 }
72
73 static void my_md5_update(my_md5_ctx *ctx,
74                           const unsigned char *input,
75                           unsigned int inputLen)
76 {
77   md5_update(ctx, inputLen, input);
78 }
79
80 static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
81 {
82   md5_digest(ctx, 16, digest);
83 }
84
85 #elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
86
87 /* When OpenSSL or wolfSSL is available, we use their MD5 functions. */
88 #if defined(USE_OPENSSL_MD5)
89 #include <openssl/md5.h>
90 #elif defined(USE_WOLFSSL_MD5)
91 #include <wolfssl/openssl/md5.h>
92 #endif
93
94 #include "curl_memory.h"
95 /* The last #include file should be: */
96 #include "memdebug.h"
97
98 typedef MD5_CTX my_md5_ctx;
99
100 static CURLcode my_md5_init(my_md5_ctx *ctx)
101 {
102   if(!MD5_Init(ctx))
103     return CURLE_OUT_OF_MEMORY;
104
105   return CURLE_OK;
106 }
107
108 static void my_md5_update(my_md5_ctx *ctx,
109                           const unsigned char *input,
110                           unsigned int len)
111 {
112   (void)MD5_Update(ctx, input, len);
113 }
114
115 static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
116 {
117   (void)MD5_Final(digest, ctx);
118 }
119
120 #elif defined(USE_MBEDTLS)
121
122 #include <mbedtls/md5.h>
123
124 #include "curl_memory.h"
125
126 /* The last #include file should be: */
127 #include "memdebug.h"
128
129 typedef mbedtls_md5_context my_md5_ctx;
130
131 static CURLcode my_md5_init(my_md5_ctx *ctx)
132 {
133 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
134   if(mbedtls_md5_starts(ctx))
135     return CURLE_OUT_OF_MEMORY;
136 #elif defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
137   if(mbedtls_md5_starts_ret(ctx))
138     return CURLE_OUT_OF_MEMORY;
139 #else
140   (void)mbedtls_md5_starts(ctx);
141 #endif
142   return CURLE_OK;
143 }
144
145 static void my_md5_update(my_md5_ctx *ctx,
146                           const unsigned char *data,
147                           unsigned int length)
148 {
149 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
150   (void) mbedtls_md5_update(ctx, data, length);
151 #else
152   (void) mbedtls_md5_update_ret(ctx, data, length);
153 #endif
154 }
155
156 static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
157 {
158 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
159   (void) mbedtls_md5_finish(ctx, digest);
160 #else
161   (void) mbedtls_md5_finish_ret(ctx, digest);
162 #endif
163 }
164
165 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
166               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
167        defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
168               (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
169       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
170               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
171
172 /* For Apple operating systems: CommonCrypto has the functions we need.
173    These functions are available on Tiger and later, as well as iOS 2.0
174    and later. If you're building for an older cat, well, sorry.
175
176    Declaring the functions as static like this seems to be a bit more
177    reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
178 #  include <CommonCrypto/CommonDigest.h>
179 #  define my_md5_ctx CC_MD5_CTX
180 #include "curl_memory.h"
181 /* The last #include file should be: */
182 #include "memdebug.h"
183
184 static CURLcode my_md5_init(my_md5_ctx *ctx)
185 {
186   if(!CC_MD5_Init(ctx))
187     return CURLE_OUT_OF_MEMORY;
188
189   return CURLE_OK;
190 }
191
192 static void my_md5_update(my_md5_ctx *ctx,
193                           const unsigned char *input,
194                           unsigned int inputLen)
195 {
196   CC_MD5_Update(ctx, input, inputLen);
197 }
198
199 static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
200 {
201   CC_MD5_Final(digest, ctx);
202 }
203
204 #elif defined(USE_WIN32_CRYPTO)
205
206 #include <wincrypt.h>
207 #include "curl_memory.h"
208 /* The last #include file should be: */
209 #include "memdebug.h"
210
211 struct md5_ctx {
212   HCRYPTPROV hCryptProv;
213   HCRYPTHASH hHash;
214 };
215 typedef struct md5_ctx my_md5_ctx;
216
217 static CURLcode my_md5_init(my_md5_ctx *ctx)
218 {
219   if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
220                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
221     return CURLE_OUT_OF_MEMORY;
222
223   if(!CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash)) {
224     CryptReleaseContext(ctx->hCryptProv, 0);
225     return CURLE_OUT_OF_MEMORY;
226   }
227
228   return CURLE_OK;
229 }
230
231 static void my_md5_update(my_md5_ctx *ctx,
232                           const unsigned char *input,
233                           unsigned int inputLen)
234 {
235   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
236 }
237
238 static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
239 {
240   unsigned long length = 0;
241   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
242   if(length == 16)
243     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
244   if(ctx->hHash)
245     CryptDestroyHash(ctx->hHash);
246   if(ctx->hCryptProv)
247     CryptReleaseContext(ctx->hCryptProv, 0);
248 }
249
250 #else
251
252 /* When no other crypto library is available we use this code segment */
253
254 /*
255  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
256  * MD5 Message-Digest Algorithm (RFC 1321).
257  *
258  * Homepage:
259  https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
260  *
261  * Author:
262  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
263  *
264  * This software was written by Alexander Peslyak in 2001.  No copyright is
265  * claimed, and the software is hereby placed in the public domain.
266  * In case this attempt to disclaim copyright and place the software in the
267  * public domain is deemed null and void, then the software is
268  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
269  * general public under the following terms:
270  *
271  * Redistribution and use in source and binary forms, with or without
272  * modification, are permitted.
273  *
274  * There's ABSOLUTELY NO WARRANTY, express or implied.
275  *
276  * (This is a heavily cut-down "BSD license".)
277  *
278  * This differs from Colin Plumb's older public domain implementation in that
279  * no exactly 32-bit integer data type is required (any 32-bit or wider
280  * unsigned integer data type will do), there's no compile-time endianness
281  * configuration, and the function prototypes match OpenSSL's.  No code from
282  * Colin Plumb's implementation has been reused; this comment merely compares
283  * the properties of the two independent implementations.
284  *
285  * The primary goals of this implementation are portability and ease of use.
286  * It is meant to be fast, but not as fast as possible.  Some known
287  * optimizations are not included to reduce source code size and avoid
288  * compile-time configuration.
289  */
290
291 #include <string.h>
292
293 /* The last #include files should be: */
294 #include "curl_memory.h"
295 #include "memdebug.h"
296
297 /* Any 32-bit or wider unsigned integer data type will do */
298 typedef unsigned int MD5_u32plus;
299
300 struct md5_ctx {
301   MD5_u32plus lo, hi;
302   MD5_u32plus a, b, c, d;
303   unsigned char buffer[64];
304   MD5_u32plus block[16];
305 };
306 typedef struct md5_ctx my_md5_ctx;
307
308 static CURLcode my_md5_init(my_md5_ctx *ctx);
309 static void my_md5_update(my_md5_ctx *ctx, const void *data,
310                           unsigned long size);
311 static void my_md5_final(unsigned char *result, my_md5_ctx *ctx);
312
313 /*
314  * The basic MD5 functions.
315  *
316  * F and G are optimized compared to their RFC 1321 definitions for
317  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
318  * implementation.
319  */
320 #define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
321 #define G(x, y, z)                      ((y) ^ ((z) & ((x) ^ (y))))
322 #define H(x, y, z)                      (((x) ^ (y)) ^ (z))
323 #define H2(x, y, z)                     ((x) ^ ((y) ^ (z)))
324 #define I(x, y, z)                      ((y) ^ ((x) | ~(z)))
325
326 /*
327  * The MD5 transformation for all four rounds.
328  */
329 #define STEP(f, a, b, c, d, x, t, s) \
330         (a) += f((b), (c), (d)) + (x) + (t); \
331         (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
332         (a) += (b);
333
334 /*
335  * SET reads 4 input bytes in little-endian byte order and stores them
336  * in a properly aligned word in host byte order.
337  *
338  * The check for little-endian architectures that tolerate unaligned
339  * memory accesses is just an optimization.  Nothing will break if it
340  * doesn't work.
341  */
342 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
343 #define SET(n) \
344         (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
345 #define GET(n) \
346         SET(n)
347 #else
348 #define SET(n) \
349         (ctx->block[(n)] = \
350         (MD5_u32plus)ptr[(n) * 4] | \
351         ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
352         ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
353         ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
354 #define GET(n) \
355         (ctx->block[(n)])
356 #endif
357
358 /*
359  * This processes one or more 64-byte data blocks, but does NOT update
360  * the bit counters.  There are no alignment requirements.
361  */
362 static const void *body(my_md5_ctx *ctx, const void *data, unsigned long size)
363 {
364   const unsigned char *ptr;
365   MD5_u32plus a, b, c, d;
366
367   ptr = (const unsigned char *)data;
368
369   a = ctx->a;
370   b = ctx->b;
371   c = ctx->c;
372   d = ctx->d;
373
374   do {
375     MD5_u32plus saved_a, saved_b, saved_c, saved_d;
376
377     saved_a = a;
378     saved_b = b;
379     saved_c = c;
380     saved_d = d;
381
382 /* Round 1 */
383     STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
384     STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
385     STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
386     STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
387     STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
388     STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
389     STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
390     STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
391     STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
392     STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
393     STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
394     STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
395     STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
396     STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
397     STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
398     STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
399
400 /* Round 2 */
401     STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
402     STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
403     STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
404     STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
405     STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
406     STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
407     STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
408     STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
409     STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
410     STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
411     STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
412     STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
413     STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
414     STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
415     STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
416     STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
417
418 /* Round 3 */
419     STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
420     STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
421     STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
422     STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
423     STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
424     STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
425     STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
426     STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
427     STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
428     STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
429     STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
430     STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
431     STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
432     STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
433     STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
434     STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
435
436 /* Round 4 */
437     STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
438     STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
439     STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
440     STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
441     STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
442     STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
443     STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
444     STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
445     STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
446     STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
447     STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
448     STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
449     STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
450     STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
451     STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
452     STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
453
454     a += saved_a;
455     b += saved_b;
456     c += saved_c;
457     d += saved_d;
458
459     ptr += 64;
460   } while(size -= 64);
461
462   ctx->a = a;
463   ctx->b = b;
464   ctx->c = c;
465   ctx->d = d;
466
467   return ptr;
468 }
469
470 static CURLcode my_md5_init(my_md5_ctx *ctx)
471 {
472   ctx->a = 0x67452301;
473   ctx->b = 0xefcdab89;
474   ctx->c = 0x98badcfe;
475   ctx->d = 0x10325476;
476
477   ctx->lo = 0;
478   ctx->hi = 0;
479
480   return CURLE_OK;
481 }
482
483 static void my_md5_update(my_md5_ctx *ctx, const void *data,
484                           unsigned long size)
485 {
486   MD5_u32plus saved_lo;
487   unsigned long used;
488
489   saved_lo = ctx->lo;
490   ctx->lo = (saved_lo + size) & 0x1fffffff;
491   if(ctx->lo < saved_lo)
492     ctx->hi++;
493   ctx->hi += (MD5_u32plus)size >> 29;
494
495   used = saved_lo & 0x3f;
496
497   if(used) {
498     unsigned long available = 64 - used;
499
500     if(size < available) {
501       memcpy(&ctx->buffer[used], data, size);
502       return;
503     }
504
505     memcpy(&ctx->buffer[used], data, available);
506     data = (const unsigned char *)data + available;
507     size -= available;
508     body(ctx, ctx->buffer, 64);
509   }
510
511   if(size >= 64) {
512     data = body(ctx, data, size & ~(unsigned long)0x3f);
513     size &= 0x3f;
514   }
515
516   memcpy(ctx->buffer, data, size);
517 }
518
519 static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
520 {
521   unsigned long used, available;
522
523   used = ctx->lo & 0x3f;
524
525   ctx->buffer[used++] = 0x80;
526
527   available = 64 - used;
528
529   if(available < 8) {
530     memset(&ctx->buffer[used], 0, available);
531     body(ctx, ctx->buffer, 64);
532     used = 0;
533     available = 64;
534   }
535
536   memset(&ctx->buffer[used], 0, available - 8);
537
538   ctx->lo <<= 3;
539   ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
540   ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
541   ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
542   ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
543   ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
544   ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
545   ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
546   ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
547
548   body(ctx, ctx->buffer, 64);
549
550   result[0] = curlx_ultouc((ctx->a)&0xff);
551   result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
552   result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
553   result[3] = curlx_ultouc(ctx->a >> 24);
554   result[4] = curlx_ultouc((ctx->b)&0xff);
555   result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
556   result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
557   result[7] = curlx_ultouc(ctx->b >> 24);
558   result[8] = curlx_ultouc((ctx->c)&0xff);
559   result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
560   result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
561   result[11] = curlx_ultouc(ctx->c >> 24);
562   result[12] = curlx_ultouc((ctx->d)&0xff);
563   result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
564   result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
565   result[15] = curlx_ultouc(ctx->d >> 24);
566
567   memset(ctx, 0, sizeof(*ctx));
568 }
569
570 #endif /* CRYPTO LIBS */
571
572 const struct HMAC_params Curl_HMAC_MD5[] = {
573   {
574     /* Hash initialization function. */
575     CURLX_FUNCTION_CAST(HMAC_hinit_func, my_md5_init),
576     /* Hash update function. */
577     CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_md5_update),
578     /* Hash computation end function. */
579     CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_md5_final),
580     /* Size of hash context structure. */
581     sizeof(my_md5_ctx),
582     /* Maximum key length. */
583     64,
584     /* Result size. */
585     16
586   }
587 };
588
589 const struct MD5_params Curl_DIGEST_MD5[] = {
590   {
591     /* Digest initialization function */
592     CURLX_FUNCTION_CAST(Curl_MD5_init_func, my_md5_init),
593     /* Digest update function */
594     CURLX_FUNCTION_CAST(Curl_MD5_update_func, my_md5_update),
595     /* Digest computation end function */
596     CURLX_FUNCTION_CAST(Curl_MD5_final_func, my_md5_final),
597     /* Size of digest context struct */
598     sizeof(my_md5_ctx),
599     /* Result size */
600     16
601   }
602 };
603
604 /*
605  * @unittest: 1601
606  * Returns CURLE_OK on success.
607  */
608 CURLcode Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
609                     const size_t len)
610 {
611   CURLcode result;
612   my_md5_ctx ctx;
613
614   result = my_md5_init(&ctx);
615   if(!result) {
616     my_md5_update(&ctx, input, curlx_uztoui(len));
617     my_md5_final(outbuffer, &ctx);
618   }
619   return result;
620 }
621
622 struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
623 {
624   struct MD5_context *ctxt;
625
626   /* Create MD5 context */
627   ctxt = malloc(sizeof(*ctxt));
628
629   if(!ctxt)
630     return ctxt;
631
632   ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
633
634   if(!ctxt->md5_hashctx) {
635     free(ctxt);
636     return NULL;
637   }
638
639   ctxt->md5_hash = md5params;
640
641   if((*md5params->md5_init_func)(ctxt->md5_hashctx)) {
642     free(ctxt->md5_hashctx);
643     free(ctxt);
644     return NULL;
645   }
646
647   return ctxt;
648 }
649
650 CURLcode Curl_MD5_update(struct MD5_context *context,
651                          const unsigned char *data,
652                          unsigned int len)
653 {
654   (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
655
656   return CURLE_OK;
657 }
658
659 CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result)
660 {
661   (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
662
663   free(context->md5_hashctx);
664   free(context);
665
666   return CURLE_OK;
667 }
668
669 #endif /* CURL_DISABLE_CRYPTO_AUTH */