commit 81e09d29ede48bc9443bd8e86c9d090ec74991e0
parent 5228ab0e225ee97e07f79bd950df24adba5780ac
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Sat, 11 Jul 2026 21:18:56 +0200
Reworked MD5 backends handling, fixed number of problems
Removed two levels dispatcher/selector, simplified to single level.
Optimised by avoiding unneeded context resets and using proper internal
API functions.
Diffstat:
20 files changed, 1882 insertions(+), 1380 deletions(-)
diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am
@@ -161,26 +161,26 @@ auth_basic_OPTSOURCES = \
if MHD_USE_MD5_INTR
md5_OPTSOURCES = \
- md5_int.c md5_int.h \
+ md5_builtin.c md5_builtin.h \
mhd_md5.h
endif
if MHD_USE_MD5_GNUTLS
md5_OPTSOURCES = \
- md5_ext.h mhd_md5.h \
- md5_ext_gnutls.c
+ md5_gnutls.c md5_gnutls.h \
+ mhd_md5.h
endif
if MHD_USE_MD5_OPENSSL
md5_OPTSOURCES = \
- md5_ext.h mhd_md5.h \
- md5_ext_openssl.c
+ md5_openssl.c md5_openssl.h \
+ mhd_md5.h
endif
if MHD_USE_MD5_MBEDTLS
md5_OPTSOURCES = \
- md5_ext.h mhd_md5.h \
- md5_ext_mbedtls.c
+ md5_mbedtls.c md5_mbedtls.h \
+ mhd_md5.h
endif
diff --git a/src/mhd2/auth_digest.c b/src/mhd2/auth_digest.c
@@ -366,7 +366,7 @@ gen_new_nonce (struct MHD_Daemon *restrict d,
# ifndef MHD_SUPPORT_MD5
# error At least one hashing algorithm must be enabled
# endif
- mhd_MD5_init_one_time (&(d_ctx.md5_ctx));
+ mhd_MD5_init (&(d_ctx.md5_ctx));
mhd_MD5_update (&(d_ctx.md5_ctx),
d->auth_dg.entropy.size,
(const void *)d->auth_dg.entropy.data);
@@ -388,7 +388,7 @@ gen_new_nonce (struct MHD_Daemon *restrict d,
/* One more hash, for the second part */
gen_num = mhd_atomic_counter_get_inc_wrap (&(d->auth_dg.num_gen_nonces));
- mhd_MD5_init_one_time (&(d_ctx.md5_ctx));
+ mhd_MD5_init (&(d_ctx.md5_ctx));
mhd_MD5_update (&(d_ctx.md5_ctx),
d->auth_dg.entropy.size,
(const void *)d->auth_dg.entropy.data);
@@ -1593,7 +1593,7 @@ digest_init_one_time (struct DigestAlgorithm *da,
# ifndef NDEBUG
da->algo_selected = true;
# endif
- mhd_MD5_init_one_time (&(da->ctx.md5_ctx));
+ mhd_MD5_init (&(da->ctx.md5_ctx));
# ifndef NDEBUG
da->ready_for_hashing = true;
# endif
@@ -1774,17 +1774,10 @@ digest_calc_hash (struct DigestAlgorithm *da,
{
case MHD_DIGEST_BASE_ALGO_MD5:
#ifdef MHD_SUPPORT_MD5
-# ifdef mhd_MD5_HAS_FINISH
mhd_MD5_finish (&da->ctx.md5_ctx, digest);
-# ifndef NDEBUG
+# ifndef NDEBUG
da->ready_for_hashing = false;
-# endif /* _DEBUG */
-# else /* ! mhd_MD5_HAS_FINISH */
- mhd_MD5_finish_reset (&da->ctx.md5_ctx, digest);
-# ifndef NDEBUG
- da->ready_for_hashing = true;
-# endif /* _DEBUG */
-# endif /* ! mhd_MD5_HAS_FINISH */
+# endif /* _DEBUG */
#else /* ! MHD_SUPPORT_MD5 */
mhd_UNREACHABLE ();
#endif /* ! MHD_SUPPORT_MD5 */
@@ -1852,11 +1845,7 @@ digest_reset (struct DigestAlgorithm *da)
{
case MHD_DIGEST_BASE_ALGO_MD5:
#ifdef MHD_SUPPORT_MD5
-# ifdef mhd_MD5_HAS_FINISH
mhd_assert (!da->ready_for_hashing);
-# else /* ! mhd_MD5_HAS_FINISH */
- mhd_assert (da->ready_for_hashing);
-# endif /* ! mhd_MD5_HAS_FINISH */
mhd_MD5_reset (&(da->ctx.md5_ctx));
# ifndef NDEBUG
da->ready_for_hashing = true;
diff --git a/src/mhd2/md5_builtin.c b/src/mhd2/md5_builtin.c
@@ -0,0 +1,563 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/md5_builtin.c
+ * @brief Calculation of MD5 digest as defined in RFC 1321
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_sys_options.h"
+
+#include "sys_bool_type.h"
+
+#include <string.h>
+#include "mhd_bithelpers.h"
+#include "mhd_align.h"
+#include "mhd_assert.h"
+
+#include "md5_builtin.h"
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1) void
+mhd_MD5_blti_init (struct mhd_Md5CtxBlti *ctx)
+{
+ /* Initial hash values, see RFC 1321, Clause 3.3 (step 3). */
+ /* Note: values specified in RFC by bytes and should be loaded in
+ little-endian mode, therefore hash values here are initialised with
+ original bytes used in little-endian order. */
+ ctx->H[0] = UINT32_C (0x67452301);
+ ctx->H[1] = UINT32_C (0xefcdab89);
+ ctx->H[2] = UINT32_C (0x98badcfe);
+ ctx->H[3] = UINT32_C (0x10325476);
+
+ /* Initialise the number of bytes. */
+ ctx->count = 0;
+}
+
+
+mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
+
+/**
+ * Base of MD5 transformation.
+ * Gets full 64 bytes block of data and updates hash values;
+ * @param H hash values
+ * @param M the data buffer with #mhd_MD5_BLOCK_SIZE bytes block
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+md5_transform (uint32_t H[mhd_MD5_HASH_SIZE_WORDS],
+ const void *restrict M)
+{
+ /* Working variables,
+ See RFC 1321, Clause 3.4 (step 4). */
+ uint32_t A = H[0];
+ uint32_t B = H[1];
+ uint32_t C = H[2];
+ uint32_t D = H[3];
+
+ /* The data buffer. See RFC 1321, Clause 3.4 (step 4). */
+ uint32_t X[16];
+
+#ifndef mhd_GET_32BIT_LE_UNALIGNED
+ if (0 != (((uintptr_t)M) % mhd_UINT32_ALIGN))
+ { /* The input data is unaligned. */
+ /* Copy the unaligned input data to the aligned buffer. */
+ memcpy (X, M, sizeof(X));
+ /* The X[] buffer itself will be used as the source of the data,
+ * but the data will be reloaded in correct bytes order on
+ * the next steps. */
+ M = (const void *)X;
+ }
+#endif /* mhd_GET_32BIT_LE_UNALIGNED */
+
+ /* Four auxiliary functions, see RFC 1321, Clause 3.4 (step 4). */
+ /* Some optimisations used. */
+/* #define F_FUNC(x,y,z) (((x)&(y)) | ((~(x))&(z))) */ /* Original version */
+#define F_FUNC(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
+/* #define G_FUNC_1(x,y,z) (((x)&(z)) | ((y)&(~(z)))) */ /* Original version */
+/* #define G_FUNC_2(x,y,z) UINT32_C(0) */ /* Original version */
+#ifndef MHD_FAVOR_SMALL_CODE
+# define G_FUNC_1(x, y, z) ((~(z)) & (y))
+# define G_FUNC_2(x, y, z) ((z) & (x))
+#else /* MHD_FAVOR_SMALL_CODE */
+# define G_FUNC_1(x, y, z) ((((x) ^ (y)) & (z)) ^ (y))
+# define G_FUNC_2(x, y, z) UINT32_C (0)
+#endif /* MHD_FAVOR_SMALL_CODE */
+#define H_FUNC(x, y, z) ((x) ^ (y) ^ (z)) /* Original version */
+/* #define I_FUNC(x,y,z) ((y) ^ ((x) | (~(z)))) */ /* Original version */
+#define I_FUNC(x, y, z) (((~(z)) | (x)) ^ (y))
+
+ /* One step of round 1 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+ The original function was modified to use X[k] and T[i] as
+ direct inputs. */
+#define MD5STEP_R1(va, vb, vc, vd, vX, vs, vT) do { \
+ (va) += (vX) + (vT); \
+ (va) += F_FUNC ((vb),(vc),(vd)); \
+ (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
+
+ /* Get value of X(k) from input data buffer.
+ See RFC 1321 Clause 3.4 (step 4). */
+#define GET_X_FROM_DATA(buf, t) \
+ mhd_GET_32BIT_LE (((const uint32_t*) (buf)) + (t))
+
+ /* One step of round 2 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+ The original function was modified to use X[k] and T[i] as
+ direct inputs. */
+#define MD5STEP_R2(va, vb, vc, vd, vX, vs, vT) do { \
+ (va) += (vX) + (vT); \
+ (va) += G_FUNC_1 ((vb),(vc),(vd)); \
+ (va) += G_FUNC_2 ((vb),(vc),(vd)); \
+ (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
+
+ /* One step of round 3 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+ The original function was modified to use X[k] and T[i] as
+ direct inputs. */
+#define MD5STEP_R3(va, vb, vc, vd, vX, vs, vT) do { \
+ (va) += (vX) + (vT); \
+ (va) += H_FUNC ((vb),(vc),(vd)); \
+ (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
+
+ /* One step of round 4 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+ The original function was modified to use X[k] and T[i] as
+ direct inputs. */
+#define MD5STEP_R4(va, vb, vc, vd, vX, vs, vT) do { \
+ (va) += (vX) + (vT); \
+ (va) += I_FUNC ((vb),(vc),(vd)); \
+ (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
+
+#if !defined(MHD_FAVOR_SMALL_CODE)
+
+ /* Round 1. */
+
+# if mhd_BYTE_ORDER == mhd_LITTLE_ENDIAN
+ if ((const void *)X == M)
+ {
+ /* The input data is already in the data buffer X[] in correct bytes
+ order. */
+ MD5STEP_R1 (A, B, C, D, X[0], 7, UINT32_C (0xd76aa478));
+ MD5STEP_R1 (D, A, B, C, X[1], 12, UINT32_C (0xe8c7b756));
+ MD5STEP_R1 (C, D, A, B, X[2], 17, UINT32_C (0x242070db));
+ MD5STEP_R1 (B, C, D, A, X[3], 22, UINT32_C (0xc1bdceee));
+
+ MD5STEP_R1 (A, B, C, D, X[4], 7, UINT32_C (0xf57c0faf));
+ MD5STEP_R1 (D, A, B, C, X[5], 12, UINT32_C (0x4787c62a));
+ MD5STEP_R1 (C, D, A, B, X[6], 17, UINT32_C (0xa8304613));
+ MD5STEP_R1 (B, C, D, A, X[7], 22, UINT32_C (0xfd469501));
+
+ MD5STEP_R1 (A, B, C, D, X[8], 7, UINT32_C (0x698098d8));
+ MD5STEP_R1 (D, A, B, C, X[9], 12, UINT32_C (0x8b44f7af));
+ MD5STEP_R1 (C, D, A, B, X[10], 17, UINT32_C (0xffff5bb1));
+ MD5STEP_R1 (B, C, D, A, X[11], 22, UINT32_C (0x895cd7be));
+
+ MD5STEP_R1 (A, B, C, D, X[12], 7, UINT32_C (0x6b901122));
+ MD5STEP_R1 (D, A, B, C, X[13], 12, UINT32_C (0xfd987193));
+ MD5STEP_R1 (C, D, A, B, X[14], 17, UINT32_C (0xa679438e));
+ MD5STEP_R1 (B, C, D, A, X[15], 22, UINT32_C (0x49b40821));
+ }
+ else /* Combined with the next 'if' */
+# endif /* mhd_BYTE_ORDER == mhd_LITTLE_ENDIAN */
+ if (1)
+ {
+ /* The input data is loaded in correct (little-endian) format before
+ calculations on each step. */
+ MD5STEP_R1 (A, B, C, D, X[0] = GET_X_FROM_DATA (M, 0), 7, \
+ UINT32_C (0xd76aa478));
+ MD5STEP_R1 (D, A, B, C, X[1] = GET_X_FROM_DATA (M, 1), 12, \
+ UINT32_C (0xe8c7b756));
+ MD5STEP_R1 (C, D, A, B, X[2] = GET_X_FROM_DATA (M, 2), 17, \
+ UINT32_C (0x242070db));
+ MD5STEP_R1 (B, C, D, A, X[3] = GET_X_FROM_DATA (M, 3), 22, \
+ UINT32_C (0xc1bdceee));
+
+ MD5STEP_R1 (A, B, C, D, X[4] = GET_X_FROM_DATA (M, 4), 7, \
+ UINT32_C (0xf57c0faf));
+ MD5STEP_R1 (D, A, B, C, X[5] = GET_X_FROM_DATA (M, 5), 12, \
+ UINT32_C (0x4787c62a));
+ MD5STEP_R1 (C, D, A, B, X[6] = GET_X_FROM_DATA (M, 6), 17, \
+ UINT32_C (0xa8304613));
+ MD5STEP_R1 (B, C, D, A, X[7] = GET_X_FROM_DATA (M, 7), 22, \
+ UINT32_C (0xfd469501));
+
+ MD5STEP_R1 (A, B, C, D, X[8] = GET_X_FROM_DATA (M, 8), 7, \
+ UINT32_C (0x698098d8));
+ MD5STEP_R1 (D, A, B, C, X[9] = GET_X_FROM_DATA (M, 9), 12, \
+ UINT32_C (0x8b44f7af));
+ MD5STEP_R1 (C, D, A, B, X[10] = GET_X_FROM_DATA (M, 10), 17, \
+ UINT32_C (0xffff5bb1));
+ MD5STEP_R1 (B, C, D, A, X[11] = GET_X_FROM_DATA (M, 11), 22, \
+ UINT32_C (0x895cd7be));
+
+ MD5STEP_R1 (A, B, C, D, X[12] = GET_X_FROM_DATA (M, 12), 7, \
+ UINT32_C (0x6b901122));
+ MD5STEP_R1 (D, A, B, C, X[13] = GET_X_FROM_DATA (M, 13), 12, \
+ UINT32_C (0xfd987193));
+ MD5STEP_R1 (C, D, A, B, X[14] = GET_X_FROM_DATA (M, 14), 17, \
+ UINT32_C (0xa679438e));
+ MD5STEP_R1 (B, C, D, A, X[15] = GET_X_FROM_DATA (M, 15), 22, \
+ UINT32_C (0x49b40821));
+ }
+
+ /* Round 2. */
+
+ MD5STEP_R2 (A, B, C, D, X[1], 5, UINT32_C (0xf61e2562));
+ MD5STEP_R2 (D, A, B, C, X[6], 9, UINT32_C (0xc040b340));
+ MD5STEP_R2 (C, D, A, B, X[11], 14, UINT32_C (0x265e5a51));
+ MD5STEP_R2 (B, C, D, A, X[0], 20, UINT32_C (0xe9b6c7aa));
+
+ MD5STEP_R2 (A, B, C, D, X[5], 5, UINT32_C (0xd62f105d));
+ MD5STEP_R2 (D, A, B, C, X[10], 9, UINT32_C (0x02441453));
+ MD5STEP_R2 (C, D, A, B, X[15], 14, UINT32_C (0xd8a1e681));
+ MD5STEP_R2 (B, C, D, A, X[4], 20, UINT32_C (0xe7d3fbc8));
+
+ MD5STEP_R2 (A, B, C, D, X[9], 5, UINT32_C (0x21e1cde6));
+ MD5STEP_R2 (D, A, B, C, X[14], 9, UINT32_C (0xc33707d6));
+ MD5STEP_R2 (C, D, A, B, X[3], 14, UINT32_C (0xf4d50d87));
+ MD5STEP_R2 (B, C, D, A, X[8], 20, UINT32_C (0x455a14ed));
+
+ MD5STEP_R2 (A, B, C, D, X[13], 5, UINT32_C (0xa9e3e905));
+ MD5STEP_R2 (D, A, B, C, X[2], 9, UINT32_C (0xfcefa3f8));
+ MD5STEP_R2 (C, D, A, B, X[7], 14, UINT32_C (0x676f02d9));
+ MD5STEP_R2 (B, C, D, A, X[12], 20, UINT32_C (0x8d2a4c8a));
+
+ /* Round 3. */
+
+ MD5STEP_R3 (A, B, C, D, X[5], 4, UINT32_C (0xfffa3942));
+ MD5STEP_R3 (D, A, B, C, X[8], 11, UINT32_C (0x8771f681));
+ MD5STEP_R3 (C, D, A, B, X[11], 16, UINT32_C (0x6d9d6122));
+ MD5STEP_R3 (B, C, D, A, X[14], 23, UINT32_C (0xfde5380c));
+
+ MD5STEP_R3 (A, B, C, D, X[1], 4, UINT32_C (0xa4beea44));
+ MD5STEP_R3 (D, A, B, C, X[4], 11, UINT32_C (0x4bdecfa9));
+ MD5STEP_R3 (C, D, A, B, X[7], 16, UINT32_C (0xf6bb4b60));
+ MD5STEP_R3 (B, C, D, A, X[10], 23, UINT32_C (0xbebfbc70));
+
+ MD5STEP_R3 (A, B, C, D, X[13], 4, UINT32_C (0x289b7ec6));
+ MD5STEP_R3 (D, A, B, C, X[0], 11, UINT32_C (0xeaa127fa));
+ MD5STEP_R3 (C, D, A, B, X[3], 16, UINT32_C (0xd4ef3085));
+ MD5STEP_R3 (B, C, D, A, X[6], 23, UINT32_C (0x04881d05));
+
+ MD5STEP_R3 (A, B, C, D, X[9], 4, UINT32_C (0xd9d4d039));
+ MD5STEP_R3 (D, A, B, C, X[12], 11, UINT32_C (0xe6db99e5));
+ MD5STEP_R3 (C, D, A, B, X[15], 16, UINT32_C (0x1fa27cf8));
+ MD5STEP_R3 (B, C, D, A, X[2], 23, UINT32_C (0xc4ac5665));
+
+ /* Round 4. */
+
+ MD5STEP_R4 (A, B, C, D, X[0], 6, UINT32_C (0xf4292244));
+ MD5STEP_R4 (D, A, B, C, X[7], 10, UINT32_C (0x432aff97));
+ MD5STEP_R4 (C, D, A, B, X[14], 15, UINT32_C (0xab9423a7));
+ MD5STEP_R4 (B, C, D, A, X[5], 21, UINT32_C (0xfc93a039));
+
+ MD5STEP_R4 (A, B, C, D, X[12], 6, UINT32_C (0x655b59c3));
+ MD5STEP_R4 (D, A, B, C, X[3], 10, UINT32_C (0x8f0ccc92));
+ MD5STEP_R4 (C, D, A, B, X[10], 15, UINT32_C (0xffeff47d));
+ MD5STEP_R4 (B, C, D, A, X[1], 21, UINT32_C (0x85845dd1));
+
+ MD5STEP_R4 (A, B, C, D, X[8], 6, UINT32_C (0x6fa87e4f));
+ MD5STEP_R4 (D, A, B, C, X[15], 10, UINT32_C (0xfe2ce6e0));
+ MD5STEP_R4 (C, D, A, B, X[6], 15, UINT32_C (0xa3014314));
+ MD5STEP_R4 (B, C, D, A, X[13], 21, UINT32_C (0x4e0811a1));
+
+ MD5STEP_R4 (A, B, C, D, X[4], 6, UINT32_C (0xf7537e82));
+ MD5STEP_R4 (D, A, B, C, X[11], 10, UINT32_C (0xbd3af235));
+ MD5STEP_R4 (C, D, A, B, X[2], 15, UINT32_C (0x2ad7d2bb));
+ MD5STEP_R4 (B, C, D, A, X[9], 21, UINT32_C (0xeb86d391));
+#else /* MHD_FAVOR_SMALL_CODE */
+ if (1)
+ {
+ static const uint32_t T[64] =
+ { UINT32_C (0xd76aa478), UINT32_C (0xe8c7b756), UINT32_C (0x242070db),
+ UINT32_C (0xc1bdceee), UINT32_C (0xf57c0faf), UINT32_C (0x4787c62a),
+ UINT32_C (0xa8304613), UINT32_C (0xfd469501), UINT32_C (0x698098d8),
+ UINT32_C (0x8b44f7af), UINT32_C (0xffff5bb1), UINT32_C (0x895cd7be),
+ UINT32_C (0x6b901122), UINT32_C (0xfd987193), UINT32_C (0xa679438e),
+ UINT32_C (0x49b40821), UINT32_C (0xf61e2562), UINT32_C (0xc040b340),
+ UINT32_C (0x265e5a51), UINT32_C (0xe9b6c7aa), UINT32_C (0xd62f105d),
+ UINT32_C (0x02441453), UINT32_C (0xd8a1e681), UINT32_C (0xe7d3fbc8),
+ UINT32_C (0x21e1cde6), UINT32_C (0xc33707d6), UINT32_C (0xf4d50d87),
+ UINT32_C (0x455a14ed), UINT32_C (0xa9e3e905), UINT32_C (0xfcefa3f8),
+ UINT32_C (0x676f02d9), UINT32_C (0x8d2a4c8a), UINT32_C (0xfffa3942),
+ UINT32_C (0x8771f681), UINT32_C (0x6d9d6122), UINT32_C (0xfde5380c),
+ UINT32_C (0xa4beea44), UINT32_C (0x4bdecfa9), UINT32_C (0xf6bb4b60),
+ UINT32_C (0xbebfbc70), UINT32_C (0x289b7ec6), UINT32_C (0xeaa127fa),
+ UINT32_C (0xd4ef3085), UINT32_C (0x04881d05), UINT32_C (0xd9d4d039),
+ UINT32_C (0xe6db99e5), UINT32_C (0x1fa27cf8), UINT32_C (0xc4ac5665),
+ UINT32_C (0xf4292244), UINT32_C (0x432aff97), UINT32_C (0xab9423a7),
+ UINT32_C (0xfc93a039), UINT32_C (0x655b59c3), UINT32_C (0x8f0ccc92),
+ UINT32_C (0xffeff47d), UINT32_C (0x85845dd1), UINT32_C (0x6fa87e4f),
+ UINT32_C (0xfe2ce6e0), UINT32_C (0xa3014314), UINT32_C (0x4e0811a1),
+ UINT32_C (0xf7537e82), UINT32_C (0xbd3af235), UINT32_C (0x2ad7d2bb),
+ UINT32_C (0xeb86d391) };
+ unsigned int i; /**< Zero-based index */
+
+ /* Round 1. */
+
+ i = 0;
+ do
+ {
+ /* The input data is loaded in correct (little-endian) format before
+ calculations on each step. */
+ MD5STEP_R1 (A, B, C, D, X[i] = GET_X_FROM_DATA (M, i), 7, T[i]);
+ ++i;
+ MD5STEP_R1 (D, A, B, C, X[i] = GET_X_FROM_DATA (M, i), 12, T[i]);
+ ++i;
+ MD5STEP_R1 (C, D, A, B, X[i] = GET_X_FROM_DATA (M, i), 17, T[i]);
+ ++i;
+ MD5STEP_R1 (B, C, D, A, X[i] = GET_X_FROM_DATA (M, i), 22, T[i]);
+ ++i;
+ } while (i < 16);
+
+ /* Round 2. */
+
+ do
+ {
+ const unsigned int idx_add = i;
+ MD5STEP_R2 (A, B, C, D, X[(1U + idx_add) & 15U], 5, T[i]);
+ ++i;
+ MD5STEP_R2 (D, A, B, C, X[(6U + idx_add) & 15U], 9, T[i]);
+ ++i;
+ MD5STEP_R2 (C, D, A, B, X[(11U + idx_add) & 15U], 14, T[i]);
+ ++i;
+ MD5STEP_R2 (B, C, D, A, X[(0U + idx_add) & 15U], 20, T[i]);
+ ++i;
+ } while (i < 32);
+
+ /* Round 3. */
+
+ do
+ {
+ const unsigned int idx_add = i;
+ MD5STEP_R3 (A, B, C, D, X[(5U + 64U - idx_add) & 15U], 4, T[i]);
+ ++i;
+ MD5STEP_R3 (D, A, B, C, X[(8U + 64U - idx_add) & 15U], 11, T[i]);
+ ++i;
+ MD5STEP_R3 (C, D, A, B, X[(11U + 64U - idx_add) & 15U], 16, T[i]);
+ ++i;
+ MD5STEP_R3 (B, C, D, A, X[(14U + 64U - idx_add) & 15U], 23, T[i]);
+ ++i;
+ } while (i < 48);
+
+ /* Round 4. */
+
+ do
+ {
+ const unsigned int idx_add = i;
+ MD5STEP_R4 (A, B, C, D, X[(0U + 64U - idx_add) & 15U], 6, T[i]);
+ ++i;
+ MD5STEP_R4 (D, A, B, C, X[(7U + 64U - idx_add) & 15U], 10, T[i]);
+ ++i;
+ MD5STEP_R4 (C, D, A, B, X[(14U + 64U - idx_add) & 15U], 15, T[i]);
+ ++i;
+ MD5STEP_R4 (B, C, D, A, X[(5U + 64U - idx_add) & 15U], 21, T[i]);
+ ++i;
+ } while (i < 64);
+ }
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+ /* Finally increment and store working variables.
+ See RFC 1321, end of Clause 3.4 (step 4). */
+
+ H[0] += A;
+ H[1] += B;
+ H[2] += C;
+ H[3] += D;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_IN_SIZE_ (3, 2) void
+mhd_MD5_blti_update (struct mhd_Md5CtxBlti *restrict ctx,
+ size_t size,
+ const void *restrict data)
+{
+ unsigned int bytes_have; /**< Number of bytes in the context buffer */
+ const uint8_t *unpr_d;
+
+ unpr_d = (const uint8_t *)data;
+
+#ifndef MHD_UNIT_TESTING
+ mhd_assert (0 != size);
+#endif
+
+ /* Note: (count & (mhd_MD5_BLOCK_SIZE-1))
+ equals (count % mhd_MD5_BLOCK_SIZE) for this block size. */
+ bytes_have = (unsigned int)(ctx->count & (mhd_MD5_BLOCK_SIZE - 1));
+ ctx->count += size;
+
+ if (0 != bytes_have)
+ {
+ unsigned int bytes_left = mhd_MD5_BLOCK_SIZE - bytes_have;
+ if (size >= bytes_left)
+ { /* Combine new data with data in the buffer and
+ process the full block. */
+ memcpy (((uint8_t *)ctx->buffer) + bytes_have,
+ unpr_d,
+ bytes_left);
+ unpr_d += bytes_left;
+ size -= bytes_left;
+ md5_transform (ctx->H, ctx->buffer);
+ bytes_have = 0;
+ }
+ }
+
+ while (mhd_MD5_BLOCK_SIZE <= size)
+ { /* Process any full blocks of new data directly,
+ without copying to the buffer. */
+ md5_transform (ctx->H, unpr_d);
+ unpr_d += mhd_MD5_BLOCK_SIZE;
+ size -= mhd_MD5_BLOCK_SIZE;
+ }
+
+ if (0 != size)
+ { /* Copy incomplete block of new data (if any)
+ to the buffer. */
+ memcpy (((uint8_t *)ctx->buffer) + bytes_have, unpr_d, size);
+ }
+}
+
+
+/**
+ * Size of "length" insertion in bits.
+ * See RFC 1321, end of Clause 3.2 (step 2).
+ */
+#define MD5_SIZE_OF_LEN_ADD_BITS 64
+
+/**
+ * Size of "length" insertion in bytes.
+ */
+#define MD5_SIZE_OF_LEN_ADD (MD5_SIZE_OF_LEN_ADD_BITS / 8)
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_OUT_ (2) void
+mhd_MD5_blti_finish (
+ struct mhd_Md5CtxBlti *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+{
+ uint64_t num_bits; /**< Number of processed bits */
+ unsigned int bytes_have; /**< Number of bytes in the context buffer */
+
+ /* Memorise the number of processed bits.
+ The padding and other data added here during the postprocessing must
+ not change the amount of hashed data. */
+ num_bits = ctx->count << 3;
+
+ /* Note: (count & (mhd_MD5_BLOCK_SIZE-1))
+ equals (count % mhd_MD5_BLOCK_SIZE) for this block size. */
+ bytes_have = (unsigned int)(ctx->count & (mhd_MD5_BLOCK_SIZE - 1));
+
+ /* Input data must be padded with a single bit "1", then with zeros and
+ the finally the length of data in bits must be added as the final bytes
+ of the last block.
+ See RFC 1321, Clauses 3.1 and 3.2 (steps 1 and 2). */
+ /* Data is always processed in form of bytes (not by individual bits),
+ therefore position of the first padding bit in byte is always
+ predefined (0x80). */
+ /* Buffer always have space for one byte at least (as full buffers are
+ processed immediately). */
+ ((uint8_t *)ctx->buffer)[bytes_have++] = 0x80;
+
+ if (mhd_MD5_BLOCK_SIZE - bytes_have < MD5_SIZE_OF_LEN_ADD)
+ { /* No space in the current block to put the total length of message.
+ Pad the current block with zeros and process it. */
+ if (bytes_have < mhd_MD5_BLOCK_SIZE)
+ memset (((uint8_t *)ctx->buffer) + bytes_have, 0,
+ mhd_MD5_BLOCK_SIZE - bytes_have);
+ /* Process the full block. */
+ md5_transform (ctx->H, ctx->buffer);
+ /* Start the new block. */
+ bytes_have = 0;
+ }
+
+ /* Pad the rest of the buffer with zeros. */
+ memset (((uint8_t *)ctx->buffer) + bytes_have, 0,
+ mhd_MD5_BLOCK_SIZE - MD5_SIZE_OF_LEN_ADD - bytes_have);
+ /* Put the number of bits in processed data as little-endian value.
+ See RFC 1321, clauses 2 and 3.2 (step 2). */
+ mhd_PUT_64BIT_LE_UNALIGN (ctx->buffer + mhd_MD5_BLOCK_SIZE_WORDS - 2,
+ num_bits);
+ /* Process the full final block. */
+ md5_transform (ctx->H, ctx->buffer);
+
+ /* Put in LE mode the hash as the final digest.
+ See RFC 1321, clauses 2 and 3.5 (step 5). */
+ if (1)
+ {
+ bool use_tmp_buf_to_align_result;
+
+#if defined(mhd_PUT_32BIT_LE_UNALIGNED)
+ use_tmp_buf_to_align_result = false;
+#elif defined(MHD_FAVOR_SMALL_CODE)
+ use_tmp_buf_to_align_result = true; /* smaller code: eliminated branch below */
+#else
+ use_tmp_buf_to_align_result =
+ (0 != ((uintptr_t)digest) % mhd_UINT32_ALIGN);
+#endif
+ if (use_tmp_buf_to_align_result)
+ {
+ /* If storing of the final result requires aligned address and
+ the destination address is not aligned or compact code is used,
+ store the final digest in aligned temporary buffer first, then
+ copy it to the destination. */
+ uint32_t alig_dgst[mhd_MD5_DIGEST_SIZE_WORDS];
+ mhd_PUT_32BIT_LE (alig_dgst + 0, ctx->H[0]);
+ mhd_PUT_32BIT_LE (alig_dgst + 1, ctx->H[1]);
+ mhd_PUT_32BIT_LE (alig_dgst + 2, ctx->H[2]);
+ mhd_PUT_32BIT_LE (alig_dgst + 3, ctx->H[3]);
+ /* Copy result to the unaligned destination address. */
+ memcpy (digest, alig_dgst, mhd_MD5_DIGEST_SIZE);
+ }
+ else
+ {
+ /* Use cast to (void*) here to mute compiler alignment warnings.
+ * Compilers are not smart enough to see that alignment has been checked. */
+ mhd_PUT_32BIT_LE ((void *)(digest + 0 * mhd_MD5_BYTES_IN_WORD), \
+ ctx->H[0]);
+ mhd_PUT_32BIT_LE ((void *)(digest + 1 * mhd_MD5_BYTES_IN_WORD), \
+ ctx->H[1]);
+ mhd_PUT_32BIT_LE ((void *)(digest + 2 * mhd_MD5_BYTES_IN_WORD), \
+ ctx->H[2]);
+ mhd_PUT_32BIT_LE ((void *)(digest + 3 * mhd_MD5_BYTES_IN_WORD), \
+ ctx->H[3]);
+ }
+ }
+
+ /* Erase potentially sensitive data. */
+ memset (ctx, 0, sizeof(struct mhd_Md5CtxBlti));
+}
+
+
+mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE
diff --git a/src/mhd2/md5_builtin.h b/src/mhd2/md5_builtin.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/md5_builtin.h
+ * @brief Calculation of MD5 digest, built-in implementation
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_MD5_BUILTIN_H
+#define MHD_MD5_BUILTIN_H 1
+
+#include "mhd_sys_options.h"
+
+#include "sys_base_types.h"
+
+/**
+ * Number of bits in single MD5 word.
+ */
+#define mhd_MD5_WORD_SIZE_BITS (32)
+
+/**
+ * Number of bytes in single MD5 word.
+ */
+#define mhd_MD5_BYTES_IN_WORD (mhd_MD5_WORD_SIZE_BITS / 8)
+
+/**
+ * Hash is kept internally as four 32-bit words.
+ * This is the intermediate hash size, used while computing the final digest.
+ */
+#define mhd_MD5_HASH_SIZE_WORDS (4)
+
+/**
+ * Size of MD5 resulting digest in bytes.
+ * This is the final digest size, not the intermediate hash.
+ */
+#define mhd_MD5_DIGEST_SIZE_WORDS mhd_MD5_HASH_SIZE_WORDS
+
+#ifndef mhd_MD5_DIGEST_SIZE
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not the intermediate hash.
+ */
+# define mhd_MD5_DIGEST_SIZE \
+ (mhd_MD5_DIGEST_SIZE_WORDS * mhd_MD5_BYTES_IN_WORD)
+#endif
+
+/**
+ * Size of MD5 single processing block in bits.
+ */
+#define mhd_MD5_BLOCK_SIZE_BITS 512
+
+/**
+ * Size of MD5 single processing block in bytes.
+ */
+#define mhd_MD5_BLOCK_SIZE (mhd_MD5_BLOCK_SIZE_BITS / 8)
+
+/**
+ * Size of MD5 single processing block in words.
+ */
+#define mhd_MD5_BLOCK_SIZE_WORDS \
+ (mhd_MD5_BLOCK_SIZE_BITS / mhd_MD5_WORD_SIZE_BITS)
+
+
+/**
+ * MD5 calculation context
+ */
+struct mhd_Md5CtxBlti
+{
+ uint32_t H[mhd_MD5_HASH_SIZE_WORDS]; /**< Intermediate hash value / digest at end of calculation */
+ uint32_t buffer[mhd_MD5_BLOCK_SIZE_WORDS]; /**< MD5 input data buffer */
+ uint64_t count; /**< number of bytes, mod 2^64 */
+};
+
+/**
+ * Indicates whether struct mhd_Md5CtxBlti has an 'ext_error' member.
+ *
+ * Set to '0' when the structure has no 'ext_error' member.
+ */
+#define mhd_MD5_BLTI_EXT_ERROR_FLAG 0
+
+/**
+ * Initialise the context for MD5 calculation.
+ *
+ * This function must not be called more than once for @a ctx without an
+ * intervening #mhd_MD5_blti_deinit().
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_blti_init (struct mhd_Md5CtxBlti *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1);
+
+/**
+ * Add a portion of data to the MD5 calculation.
+ *
+ * @param ctx the calculation context
+ * @param size number of bytes in @a data, must not be 0
+ * @param data bytes to add to hash
+ */
+MHD_INTERNAL void
+mhd_MD5_blti_update (struct mhd_Md5CtxBlti *restrict ctx,
+ size_t size,
+ const void *restrict data)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_IN_SIZE_ (3, 2);
+
+/**
+ * Finalise the MD5 calculation and return the digest.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+MHD_INTERNAL void
+mhd_MD5_blti_finish (
+ struct mhd_Md5CtxBlti *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_OUT_ (2);
+
+/**
+ * Reset the context for a new MD5 calculation.
+ *
+ * This function may be called only after #mhd_MD5_blti_finish(). If the context
+ * is subsequently reused for a new calculation, this function must be called
+ * before starting that calculation.
+ *
+ * @param ctx the calculation context
+ */
+#define mhd_MD5_blti_reset(ctx) mhd_MD5_blti_init((ctx))
+
+/**
+ * Deinitialise the MD5 calculation context.
+ *
+ * After calling this function, @a ctx can be reinitialised with
+ * #mhd_MD5_blti_init().
+ *
+ * @param ctx the calculation context
+ */
+#define mhd_MD5_blti_deinit(ctx) ((void) (ctx))
+
+/**
+ * Indicates whether #mhd_MD5_blti_deinit() is a real function or a no-op.
+ *
+ * Set to '1' as #mhd_MD5_blti_deinit() is a no-op.
+ */
+#define mhd_MD5_BLTI_DEINIT_NOOP_FLAG 1
+
+#endif /* MHD_MD5_BUILTIN_H */
diff --git a/src/mhd2/md5_ext.h b/src/mhd2/md5_ext.h
@@ -1,131 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
-/*
- This file is part of GNU libmicrohttpd.
- Copyright (C) 2022-2024 Evgeny Grin (Karlson2k)
-
- GNU libmicrohttpd is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- GNU libmicrohttpd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- Alternatively, you can redistribute GNU libmicrohttpd and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version, together
- with the eCos exception, as follows:
-
- As a special exception, if other files instantiate templates or
- use macros or inline functions from this file, or you compile this
- file and link it with other works to produce a work based on this
- file, this file does not by itself cause the resulting work to be
- covered by the GNU General Public License. However the source code
- for this file must still be made available in accordance with
- section (3) of the GNU General Public License v2.
-
- This exception does not invalidate any other reasons why a work
- based on this file might be covered by the GNU General Public
- License.
-
- You should have received copies of the GNU Lesser General Public
- License and the GNU General Public License along with this library;
- if not, see <https://www.gnu.org/licenses/>.
-*/
-/**
- * @file src/mhd2/md5_ext.h
- * @brief Wrapper declarations for MD5 calculation performed by TLS library
- * @author Karlson2k (Evgeny Grin)
- */
-#ifndef MHD_MD5_EXT_H
-#define MHD_MD5_EXT_H 1
-
-#include "mhd_sys_options.h"
-
-#include "sys_base_types.h"
-
-/**
- * Size of MD5 resulting digest in bytes
- * This is the final digest size, not intermediate hash.
- */
-#define mhd_MD5_DIGEST_SIZE (16)
-
-#ifndef MHD_MD5_Context
-# define MHD_MD5_Context void
-#endif
-
-/**
- * Indicates that struct mhd_Md5CtxExt has 'ext_error'
- */
-#define mhd_MD5_HAS_EXT_ERROR 1
-
-/**
- * MD5 calculation context
- */
-struct mhd_Md5CtxExt
-{
- MHD_MD5_Context *handle; /**< Hash calculation handle */
- int ext_error; /**< Non-zero if external error occurs during init or hashing */
-};
-
-/**
- * Indicates that mhd_MD5_init_one_time() function is present.
- */
-#define mhd_MD5_HAS_INIT_ONE_TIME 1
-
-/**
- * Initialise structure for MD5 calculation, allocate resources.
- *
- * This function must not be called more than one time for @a ctx.
- *
- * @param ctx the calculation context
- */
-void
-mhd_MD5_init_one_time (struct mhd_Md5CtxExt *ctx);
-
-
-/**
- * MD5 process portion of bytes.
- *
- * @param ctx the calculation context
- * @param size number of bytes in @a data, must not be 0
- * @param data bytes to add to hash
- */
-void
-mhd_MD5_update (struct mhd_Md5CtxExt *restrict ctx,
- size_t size,
- const uint8_t *restrict data);
-
-
-/**
- * Indicates that mhd_MD5_finish_reset() function is available
- */
-#define mhd_MD5_HAS_FINISH_RESET 1
-
-/**
- * Finalise MD5 calculation, return digest, reset hash calculation.
- *
- * @param ctx the calculation context
- * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
- */
-void
-mhd_MD5_finish_reset (struct mhd_Md5CtxExt *restrict ctx,
- uint8_t digest[mhd_MD5_DIGEST_SIZE]);
-
-/**
- * Indicates that mhd_MD5_deinit() function is present
- */
-#define mhd_MD5_HAS_DEINIT 1
-
-/**
- * Free allocated resources.
- *
- * @param[in] ctx the calculation context
- */
-void
-mhd_MD5_deinit (struct mhd_Md5CtxExt *ctx);
-
-#endif /* MHD_MD5_EXT_H */
diff --git a/src/mhd2/md5_ext_gnutls.c b/src/mhd2/md5_ext_gnutls.c
@@ -1,129 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
-/*
- This file is part of GNU libmicrohttpd.
- Copyright (C) 2022-2023 Evgeny Grin (Karlson2k)
-
- GNU libmicrohttpd is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- GNU libmicrohttpd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- Alternatively, you can redistribute GNU libmicrohttpd and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version, together
- with the eCos exception, as follows:
-
- As a special exception, if other files instantiate templates or
- use macros or inline functions from this file, or you compile this
- file and link it with other works to produce a work based on this
- file, this file does not by itself cause the resulting work to be
- covered by the GNU General Public License. However the source code
- for this file must still be made available in accordance with
- section (3) of the GNU General Public License v2.
-
- This exception does not invalidate any other reasons why a work
- based on this file might be covered by the GNU General Public
- License.
-
- You should have received copies of the GNU Lesser General Public
- License and the GNU General Public License along with this library;
- if not, see <https://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file microhttpd/md5_ext.c
- * @brief Wrapper for MD5 calculation performed by TLS library
- * @author Karlson2k (Evgeny Grin)
- */
-
-#include <gnutls/crypto.h>
-#define MHD_MD5_Context struct hash_hd_st
-#include "md5_ext.h"
-#include "mhd_assert.h"
-
-
-/**
- * Initialise structure for MD5 calculation, allocate resources.
- *
- * This function must not be called more than one time for @a ctx.
- *
- * @param ctx the calculation context
- */
-void
-mhd_MD5_init_one_time (struct mhd_Md5CtxExt *ctx)
-{
- ctx->handle = NULL;
- ctx->ext_error = gnutls_hash_init (&ctx->handle,
- GNUTLS_DIG_MD5);
- if ((0 != ctx->ext_error) && (NULL != ctx->handle))
- {
- /* GnuTLS may return initialisation error and set the handle at the
- same time. Such handle cannot be used for calculations.
- Note: GnuTLS may also return an error and NOT set the handle. */
- mhd_MD5_deinit (ctx);
- }
-
- /* If handle is NULL, the error must be set */
- mhd_assert ((NULL != ctx->handle) || (0 != ctx->ext_error));
- /* If error is set, the handle must be NULL */
- mhd_assert ((0 == ctx->ext_error) || (NULL == ctx->handle));
-}
-
-
-/**
- * Process portion of bytes.
- *
- * @param ctx the calculation context
- * @param data bytes to add to hash
- * @param length number of bytes in @a data
- */
-void
-mhd_MD5_update (struct mhd_Md5CtxExt *ctx,
- size_t size,
- const uint8_t *data)
-{
- mhd_assert (0 != size);
- if (0 == ctx->ext_error)
- ctx->ext_error = gnutls_hash (ctx->handle,
- data,
- size);
-}
-
-
-/**
- * Finalise MD5 calculation, return digest, reset hash calculation.
- *
- * @param ctx the calculation context
- * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
- */
-void
-mhd_MD5_finish_reset (struct mhd_Md5CtxExt *ctx,
- uint8_t digest[mhd_MD5_DIGEST_SIZE])
-{
- if (0 == ctx->ext_error)
- gnutls_hash_output (ctx->handle,
- digest);
-}
-
-
-/**
- * Free allocated resources.
- *
- * @param ctx the calculation context
- */
-void
-mhd_MD5_deinit (struct mhd_Md5CtxExt *ctx)
-{
- if (NULL != ctx->handle)
- {
- gnutls_hash_deinit (ctx->handle,
- NULL);
- ctx->handle = NULL;
- }
-}
diff --git a/src/mhd2/md5_ext_mbedtls.c b/src/mhd2/md5_ext_mbedtls.c
@@ -1,139 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
-/*
- This file is part of GNU libmicrohttpd.
- Copyright (C) 2025 Christian Grothoff
-
- GNU libmicrohttpd is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- GNU libmicrohttpd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- Alternatively, you can redistribute GNU libmicrohttpd and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version, together
- with the eCos exception, as follows:
-
- As a special exception, if other files instantiate templates or
- use macros or inline functions from this file, or you compile this
- file and link it with other works to produce a work based on this
- file, this file does not by itself cause the resulting work to be
- covered by the GNU General Public License. However the source code
- for this file must still be made available in accordance with
- section (3) of the GNU General Public License v2.
-
- This exception does not invalidate any other reasons why a work
- based on this file might be covered by the GNU General Public
- License.
-
- You should have received copies of the GNU Lesser General Public
- License and the GNU General Public License along with this library;
- if not, see <https://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file microhttpd/md5_ext_mbedtls.c
- * @brief Wrapper for MD5 calculation performed by mbedTLS library
- * @author Christian Grothoff
- */
-
-#include <mbedtls/md5.h>
-#define MHD_MD5_Context mbedtls_md5_context
-#include "md5_ext.h"
-#include "mhd_assert.h"
-
-
-/**
- * Initialise structure for MD5 calculation, allocate resources.
- *
- * This function must not be called more than one time for @a ctx.
- *
- * @param ctx the calculation context
- */
-void
-mhd_MD5_init_one_time (struct mhd_Md5CtxExt *ctx)
-{
- ctx->ext_error = 0;
- ctx->handle = (mbedtls_md5_context *)malloc (
- sizeof (mbedtls_md5_context));
- if (NULL == ctx->handle)
- {
- ctx->ext_error = 1; /* Allocation failure */
- return;
- }
- mbedtls_md5_init (ctx->handle);
- ctx->ext_error = mbedtls_md5_starts_ret (ctx->handle);
- if (0 != ctx->ext_error)
- {
- mhd_MD5_deinit (ctx->handle);
- }
-
- /* If handle is NULL, the error must be set */
- mhd_assert ((NULL != ctx->handle) || (0 != ctx->ext_error));
- /* If error is set, the handle must be NULL */
- mhd_assert ((0 == ctx->ext_error) || (NULL == ctx->handle));
-}
-
-
-/**
- * Process portion of bytes.
- *
- * @param ctx the calculation context
- * @param data bytes to add to hash
- * @param length number of bytes in @a data
- */
-void
-mhd_MD5_update (struct mhd_Md5CtxExt *ctx,
- size_t size,
- const uint8_t *data)
-{
- mhd_assert (0 != size);
-
- if (0 == ctx->ext_error)
- ctx->ext_error = mbedtls_md5_update_ret (ctx->handle,
- data,
- size);
-}
-
-
-/**
- * Finalise MD5 calculation, return digest, reset hash calculation.
- *
- * @param ctx the calculation context
- * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
- */
-void
-mhd_MD5_finish_reset (struct mhd_Md5CtxExt *ctx,
- uint8_t digest[mhd_MD5_DIGEST_SIZE])
-{
- if (0 != ctx->ext_error)
- return;
- ctx->ext_error = mbedtls_md5_finish_ret (ctx->handle,
- digest);
- if (0 != ctx->ext_error)
- return;
- /* Reset for potential reuse */
- ctx->ext_error = mbedtls_md5_starts_ret (ctx->handle);
-}
-
-
-/**
- * Free allocated resources.
- *
- * @param ctx the calculation context
- */
-void
-mhd_MD5_deinit (struct mhd_Md5CtxExt *ctx)
-{
- if (NULL != ctx->handle)
- {
- mbedtls_md5_free (ctx->handle);
- free (ctx->handle);
- ctx->handle = NULL;
- }
-}
diff --git a/src/mhd2/md5_ext_openssl.c b/src/mhd2/md5_ext_openssl.c
@@ -1,153 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
-/*
- This file is part of GNU libmicrohttpd.
- Copyright (C) 2025 Christian Grothoff
-
- GNU libmicrohttpd is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- GNU libmicrohttpd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- Alternatively, you can redistribute GNU libmicrohttpd and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version, together
- with the eCos exception, as follows:
-
- As a special exception, if other files instantiate templates or
- use macros or inline functions from this file, or you compile this
- file and link it with other works to produce a work based on this
- file, this file does not by itself cause the resulting work to be
- covered by the GNU General Public License. However the source code
- for this file must still be made available in accordance with
- section (3) of the GNU General Public License v2.
-
- This exception does not invalidate any other reasons why a work
- based on this file might be covered by the GNU General Public
- License.
-
- You should have received copies of the GNU Lesser General Public
- License and the GNU General Public License along with this library;
- if not, see <https://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file microhttpd/md5_ext_openssl.c
- * @brief Wrapper for MD5 calculation performed by OpenSSL library
- * @author Christian grothoff
- */
-
-#include <openssl/evp.h>
-#define MHD_MD5_Context EVP_MD_CTX
-#include "md5_ext.h"
-#include "mhd_assert.h"
-
-
-/**
- * Initialise structure for MD5 calculation, allocate resources.
- *
- * This function must not be called more than one time for @a ctx.
- *
- * @param ctx the calculation context
- */
-void
-mhd_MD5_init_one_time (struct mhd_Md5CtxExt *ctx)
-{
- ctx->ext_error = 0;
- ctx->handle = EVP_MD_CTX_new ();
- if (NULL == ctx->handle)
- {
- ctx->ext_error = 1; /* Allocation failure */
- return;
- }
- if (1 != EVP_DigestInit_ex (ctx->handle,
- EVP_md5 (),
- NULL))
- {
- ctx->ext_error = 1; /* Initialization failure */
- mhd_MD5_deinit (ctx);
- }
-
- /* If handle is NULL, the error must be set */
- mhd_assert ((NULL != ctx->handle) || (0 != ctx->ext_error));
- /* If error is set, the handle must be NULL */
- mhd_assert ((0 == ctx->ext_error) || (NULL == ctx->handle));
-}
-
-
-/**
- * Process portion of bytes.
- *
- * @param ctx the calculation context
- * @param size number of bytes in @a data, must not be 0
- * @param data bytes to add to hash
- */
-void
-mhd_MD5_update (struct mhd_Md5CtxExt *ctx,
- size_t size,
- const uint8_t *data)
-{
- mhd_assert (0 != size);
-
- if (0 == ctx->ext_error)
- {
- if (1 != EVP_DigestUpdate (ctx->handle,
- data,
- size))
- ctx->ext_error = 1;
- }
-}
-
-
-/**
- * Finalise MD5 calculation, return digest, reset hash calculation.
- *
- * @param ctx the calculation context
- * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
- */
-void
-mhd_MD5_finish_reset (struct mhd_Md5CtxExt *ctx,
- uint8_t digest[mhd_MD5_DIGEST_SIZE])
-{
- unsigned int len;
-
- if (0 != ctx->ext_error)
- return;
- if (1 != EVP_DigestFinal_ex (ctx->handle,
- digest,
- &len))
- {
- ctx->ext_error = 1;
- return;
- }
- mhd_assert (mhd_MD5_DIGEST_SIZE == len);
- /* Reset for potential reuse */
- if (1 != EVP_DigestInit_ex (ctx->handle,
- EVP_md5 (),
- NULL))
- {
- ctx->ext_error = 1;
- mhd_MD5_deinit (ctx);
- }
-}
-
-
-/**
- * Free allocated resources.
- *
- * @param[in] ctx the calculation context
- */
-void
-mhd_MD5_deinit (struct mhd_Md5CtxExt *ctx)
-{
- if (NULL != ctx->handle)
- {
- EVP_MD_CTX_free (ctx->handle);
- ctx->handle = NULL;
- }
-}
diff --git a/src/mhd2/md5_gnutls.c b/src/mhd2/md5_gnutls.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/md5_gnutls.c
+ * @brief Wrapper for MD5 calculation performed by GnuTLS backend
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_sys_options.h"
+
+#include <gnutls/crypto.h>
+#include "mhd_assert.h"
+
+#include "md5_gnutls.h"
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1) void
+mhd_MD5_gtls_init (struct mhd_Md5CtxGtls *ctx)
+{
+ ctx->handle = NULL;
+ ctx->ext_error = gnutls_hash_init (&ctx->handle,
+ GNUTLS_DIG_MD5);
+ if ((0 != ctx->ext_error) && (NULL != ctx->handle))
+ {
+ /* GnuTLS may return an initialisation error and set the handle at the
+ same time. Such a handle cannot be used for calculations.
+ Note: GnuTLS may also return an error and NOT set the handle. */
+ mhd_MD5_gtls_deinit (ctx);
+ }
+
+ /* If handle is NULL, the error must be set */
+ mhd_assert ((NULL != ctx->handle) || (0 != ctx->ext_error));
+ /* If error is set, the handle must be NULL */
+ mhd_assert ((0 == ctx->ext_error) || (NULL == ctx->handle));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_IN_SIZE_ (3, 2) void
+mhd_MD5_gtls_update (struct mhd_Md5CtxGtls *restrict ctx,
+ size_t size,
+ const void *restrict data)
+{
+#ifndef MHD_UNIT_TESTING
+ mhd_assert (0 != size);
+#endif
+
+ if (0 == ctx->ext_error)
+ ctx->ext_error = gnutls_hash (ctx->handle,
+ data,
+ size);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_OUT_ (2) void
+mhd_MD5_gtls_finish (
+ struct mhd_Md5CtxGtls *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+{
+ if (0 == ctx->ext_error)
+ gnutls_hash_output (ctx->handle,
+ digest);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_INOUT_ (1) void
+mhd_MD5_gtls_deinit (struct mhd_Md5CtxGtls *ctx)
+{
+ if (NULL != ctx->handle)
+ {
+ gnutls_hash_deinit (ctx->handle,
+ NULL);
+ ctx->handle = NULL;
+ }
+}
diff --git a/src/mhd2/md5_gnutls.h b/src/mhd2/md5_gnutls.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+/**
+ * @file src/mhd2/md5_gnutls.h
+ * @brief Wrapper declarations for MD5 calculation performed by GnuTLS backend
+ * @author Karlson2k (Evgeny Grin)
+ */
+#ifndef MHD_MD5_GNUTLS_H
+#define MHD_MD5_GNUTLS_H 1
+
+#include "mhd_sys_options.h"
+
+#include "sys_base_types.h"
+
+#ifndef mhd_MD5_DIGEST_SIZE
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not the intermediate hash.
+ */
+# define mhd_MD5_DIGEST_SIZE (16)
+#endif
+
+/* Forward declaration for GnuTLS struct, to avoid including large header */
+struct hash_hd_st;
+
+/**
+ * MD5 calculation context
+ */
+struct mhd_Md5CtxGtls
+{
+ struct hash_hd_st *handle; /**< Hash calculation handle */
+ int ext_error; /**< Error number reported by the hashing backend (zero if no error) */
+};
+
+/**
+ * Indicates whether struct mhd_Md5CtxGtls has an 'ext_error' member.
+ *
+ * Set to '1' when the structure has an 'ext_error' member.
+ */
+#define mhd_MD5_GTLS_EXT_ERROR_FLAG 1
+
+/**
+ * Initialise the context for MD5 calculation.
+ *
+ * This function must not be called more than once for @a ctx without an
+ * intervening #mhd_MD5_gtls_deinit().
+ *
+ * Whether or not an error is reported, #mhd_MD5_gtls_deinit() must be
+ * called for @a ctx once this function has returned.
+ *
+ * The error state in @a ctx is set according to the result: cleared on
+ * success, set on failure.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_gtls_init (struct mhd_Md5CtxGtls *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1);
+
+/**
+ * Add a portion of data to the MD5 calculation.
+ *
+ * If @a ctx already has a recorded error, this function does nothing.
+ * Otherwise, if the operation fails, the error is recorded in @a ctx.
+ *
+ * @param ctx the calculation context
+ * @param size number of bytes in @a data, must not be 0
+ * @param data bytes to add to hash
+ */
+MHD_INTERNAL void
+mhd_MD5_gtls_update (struct mhd_Md5CtxGtls *restrict ctx,
+ size_t size,
+ const void *restrict data)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_IN_SIZE_ (3, 2);
+
+/**
+ * Finalise the MD5 calculation and return the digest.
+ *
+ * If @a ctx already has a recorded error, this function does nothing.
+ *
+ * The GnuTLS backend resets the underlying hash handle during this operation.
+ * If the context is reused, the caller must still invoke #mhd_MD5_gtls_reset()
+ * afterwards to follow the common MD5 context lifecycle; that reset operation
+ * is a no-op.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+MHD_INTERNAL void
+mhd_MD5_gtls_finish (
+ struct mhd_Md5CtxGtls *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_OUT_ (2);
+
+/**
+ * Reset the context for a new MD5 calculation.
+ *
+ * This function may be called only after #mhd_MD5_gtls_finish(). If the context
+ * is subsequently reused for a new calculation, this function must be called
+ * before starting that calculation.
+ *
+ * This operation is a no-op; the recorded error state in @a ctx is preserved.
+ *
+ * @param ctx the calculation context
+ */
+#define mhd_MD5_gtls_reset(ctx) ((void) (ctx))
+
+/**
+ * Deinitialise the MD5 calculation context.
+ *
+ * After calling this function, @a ctx can be reinitialised with
+ * #mhd_MD5_gtls_init().
+ *
+ * The recorded error state in @a ctx is preserved.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_gtls_deinit (struct mhd_Md5CtxGtls *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+/**
+ * Indicates whether #mhd_MD5_gtls_deinit() is a real function or a no-op.
+ *
+ * Set to '0' as #mhd_MD5_gtls_deinit() is a real function.
+ */
+#define mhd_MD5_GTLS_DEINIT_NOOP_FLAG 0
+
+#endif /* MHD_MD5_GNUTLS_H */
diff --git a/src/mhd2/md5_int.c b/src/mhd2/md5_int.c
@@ -1,557 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
-/*
- This file is part of GNU libmicrohttpd.
- Copyright (C) 2022-2024 Evgeny Grin (Karlson2k)
-
- GNU libmicrohttpd is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- GNU libmicrohttpd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- Alternatively, you can redistribute GNU libmicrohttpd and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version, together
- with the eCos exception, as follows:
-
- As a special exception, if other files instantiate templates or
- use macros or inline functions from this file, or you compile this
- file and link it with other works to produce a work based on this
- file, this file does not by itself cause the resulting work to be
- covered by the GNU General Public License. However the source code
- for this file must still be made available in accordance with
- section (3) of the GNU General Public License v2.
-
- This exception does not invalidate any other reasons why a work
- based on this file might be covered by the GNU General Public
- License.
-
- You should have received copies of the GNU Lesser General Public
- License and the GNU General Public License along with this library;
- if not, see <https://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file src/mhd2/md5_int.c
- * @brief Calculation of MD5 digest as defined in RFC 1321
- * @author Karlson2k (Evgeny Grin)
- */
-
-#include "mhd_sys_options.h"
-
-#include "sys_bool_type.h"
-
-#include <string.h>
-#include "mhd_bithelpers.h"
-#include "mhd_align.h"
-#include "mhd_assert.h"
-
-#include "md5_int.h"
-
-MHD_INTERNAL void MHD_FN_PAR_NONNULL_ALL_
-mhd_MD5_init (struct mhd_Md5CtxInt *ctx)
-{
- /* Initial hash values, see RFC 1321, Clause 3.3 (step 3). */
- /* Note: values specified in RFC by bytes and should be loaded in
- little-endian mode, therefore hash values here are initialised with
- original bytes used in little-endian order. */
- ctx->H[0] = UINT32_C (0x67452301);
- ctx->H[1] = UINT32_C (0xefcdab89);
- ctx->H[2] = UINT32_C (0x98badcfe);
- ctx->H[3] = UINT32_C (0x10325476);
-
- /* Initialise the number of bytes. */
- ctx->count = 0;
-}
-
-
-mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
-
-/**
- * Base of MD5 transformation.
- * Gets full 64 bytes block of data and updates hash values;
- * @param H hash values
- * @param M the data buffer with #mhd_MD5_BLOCK_SIZE bytes block
- */
-static MHD_FN_PAR_NONNULL_ALL_ void
-md5_transform (uint32_t H[mhd_MD5_HASH_SIZE_WORDS],
- const void *restrict M)
-{
- /* Working variables,
- See RFC 1321, Clause 3.4 (step 4). */
- uint32_t A = H[0];
- uint32_t B = H[1];
- uint32_t C = H[2];
- uint32_t D = H[3];
-
- /* The data buffer. See RFC 1321, Clause 3.4 (step 4). */
- uint32_t X[16];
-
-#ifndef mhd_GET_32BIT_LE_UNALIGNED
- if (0 != (((uintptr_t)M) % mhd_UINT32_ALIGN))
- { /* The input data is unaligned. */
- /* Copy the unaligned input data to the aligned buffer. */
- memcpy (X, M, sizeof(X));
- /* The X[] buffer itself will be used as the source of the data,
- * but the data will be reloaded in correct bytes order on
- * the next steps. */
- M = (const void *)X;
- }
-#endif /* mhd_GET_32BIT_LE_UNALIGNED */
-
- /* Four auxiliary functions, see RFC 1321, Clause 3.4 (step 4). */
- /* Some optimisations used. */
-/* #define F_FUNC(x,y,z) (((x)&(y)) | ((~(x))&(z))) */ /* Original version */
-#define F_FUNC(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
-/* #define G_FUNC_1(x,y,z) (((x)&(z)) | ((y)&(~(z)))) */ /* Original version */
-/* #define G_FUNC_2(x,y,z) UINT32_C(0) */ /* Original version */
-#ifndef MHD_FAVOR_SMALL_CODE
-# define G_FUNC_1(x, y, z) ((~(z)) & (y))
-# define G_FUNC_2(x, y, z) ((z) & (x))
-#else /* MHD_FAVOR_SMALL_CODE */
-# define G_FUNC_1(x, y, z) ((((x) ^ (y)) & (z)) ^ (y))
-# define G_FUNC_2(x, y, z) UINT32_C (0)
-#endif /* MHD_FAVOR_SMALL_CODE */
-#define H_FUNC(x, y, z) ((x) ^ (y) ^ (z)) /* Original version */
-/* #define I_FUNC(x,y,z) ((y) ^ ((x) | (~(z)))) */ /* Original version */
-#define I_FUNC(x, y, z) (((~(z)) | (x)) ^ (y))
-
- /* One step of round 1 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
- The original function was modified to use X[k] and T[i] as
- direct inputs. */
-#define MD5STEP_R1(va, vb, vc, vd, vX, vs, vT) do { \
- (va) += (vX) + (vT); \
- (va) += F_FUNC ((vb),(vc),(vd)); \
- (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
-
- /* Get value of X(k) from input data buffer.
- See RFC 1321 Clause 3.4 (step 4). */
-#define GET_X_FROM_DATA(buf, t) \
- mhd_GET_32BIT_LE (((const uint32_t*) (buf)) + (t))
-
- /* One step of round 2 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
- The original function was modified to use X[k] and T[i] as
- direct inputs. */
-#define MD5STEP_R2(va, vb, vc, vd, vX, vs, vT) do { \
- (va) += (vX) + (vT); \
- (va) += G_FUNC_1 ((vb),(vc),(vd)); \
- (va) += G_FUNC_2 ((vb),(vc),(vd)); \
- (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
-
- /* One step of round 3 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
- The original function was modified to use X[k] and T[i] as
- direct inputs. */
-#define MD5STEP_R3(va, vb, vc, vd, vX, vs, vT) do { \
- (va) += (vX) + (vT); \
- (va) += H_FUNC ((vb),(vc),(vd)); \
- (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
-
- /* One step of round 4 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
- The original function was modified to use X[k] and T[i] as
- direct inputs. */
-#define MD5STEP_R4(va, vb, vc, vd, vX, vs, vT) do { \
- (va) += (vX) + (vT); \
- (va) += I_FUNC ((vb),(vc),(vd)); \
- (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
-
-#if !defined(MHD_FAVOR_SMALL_CODE)
-
- /* Round 1. */
-
-# if mhd_BYTE_ORDER == mhd_LITTLE_ENDIAN
- if ((const void *)X == M)
- {
- /* The input data is already in the data buffer X[] in correct bytes
- order. */
- MD5STEP_R1 (A, B, C, D, X[0], 7, UINT32_C (0xd76aa478));
- MD5STEP_R1 (D, A, B, C, X[1], 12, UINT32_C (0xe8c7b756));
- MD5STEP_R1 (C, D, A, B, X[2], 17, UINT32_C (0x242070db));
- MD5STEP_R1 (B, C, D, A, X[3], 22, UINT32_C (0xc1bdceee));
-
- MD5STEP_R1 (A, B, C, D, X[4], 7, UINT32_C (0xf57c0faf));
- MD5STEP_R1 (D, A, B, C, X[5], 12, UINT32_C (0x4787c62a));
- MD5STEP_R1 (C, D, A, B, X[6], 17, UINT32_C (0xa8304613));
- MD5STEP_R1 (B, C, D, A, X[7], 22, UINT32_C (0xfd469501));
-
- MD5STEP_R1 (A, B, C, D, X[8], 7, UINT32_C (0x698098d8));
- MD5STEP_R1 (D, A, B, C, X[9], 12, UINT32_C (0x8b44f7af));
- MD5STEP_R1 (C, D, A, B, X[10], 17, UINT32_C (0xffff5bb1));
- MD5STEP_R1 (B, C, D, A, X[11], 22, UINT32_C (0x895cd7be));
-
- MD5STEP_R1 (A, B, C, D, X[12], 7, UINT32_C (0x6b901122));
- MD5STEP_R1 (D, A, B, C, X[13], 12, UINT32_C (0xfd987193));
- MD5STEP_R1 (C, D, A, B, X[14], 17, UINT32_C (0xa679438e));
- MD5STEP_R1 (B, C, D, A, X[15], 22, UINT32_C (0x49b40821));
- }
- else /* Combined with the next 'if' */
-# endif /* mhd_BYTE_ORDER == mhd_LITTLE_ENDIAN */
- if (1)
- {
- /* The input data is loaded in correct (little-endian) format before
- calculations on each step. */
- MD5STEP_R1 (A, B, C, D, X[0] = GET_X_FROM_DATA (M, 0), 7, \
- UINT32_C (0xd76aa478));
- MD5STEP_R1 (D, A, B, C, X[1] = GET_X_FROM_DATA (M, 1), 12, \
- UINT32_C (0xe8c7b756));
- MD5STEP_R1 (C, D, A, B, X[2] = GET_X_FROM_DATA (M, 2), 17, \
- UINT32_C (0x242070db));
- MD5STEP_R1 (B, C, D, A, X[3] = GET_X_FROM_DATA (M, 3), 22, \
- UINT32_C (0xc1bdceee));
-
- MD5STEP_R1 (A, B, C, D, X[4] = GET_X_FROM_DATA (M, 4), 7, \
- UINT32_C (0xf57c0faf));
- MD5STEP_R1 (D, A, B, C, X[5] = GET_X_FROM_DATA (M, 5), 12, \
- UINT32_C (0x4787c62a));
- MD5STEP_R1 (C, D, A, B, X[6] = GET_X_FROM_DATA (M, 6), 17, \
- UINT32_C (0xa8304613));
- MD5STEP_R1 (B, C, D, A, X[7] = GET_X_FROM_DATA (M, 7), 22, \
- UINT32_C (0xfd469501));
-
- MD5STEP_R1 (A, B, C, D, X[8] = GET_X_FROM_DATA (M, 8), 7, \
- UINT32_C (0x698098d8));
- MD5STEP_R1 (D, A, B, C, X[9] = GET_X_FROM_DATA (M, 9), 12, \
- UINT32_C (0x8b44f7af));
- MD5STEP_R1 (C, D, A, B, X[10] = GET_X_FROM_DATA (M, 10), 17, \
- UINT32_C (0xffff5bb1));
- MD5STEP_R1 (B, C, D, A, X[11] = GET_X_FROM_DATA (M, 11), 22, \
- UINT32_C (0x895cd7be));
-
- MD5STEP_R1 (A, B, C, D, X[12] = GET_X_FROM_DATA (M, 12), 7, \
- UINT32_C (0x6b901122));
- MD5STEP_R1 (D, A, B, C, X[13] = GET_X_FROM_DATA (M, 13), 12, \
- UINT32_C (0xfd987193));
- MD5STEP_R1 (C, D, A, B, X[14] = GET_X_FROM_DATA (M, 14), 17, \
- UINT32_C (0xa679438e));
- MD5STEP_R1 (B, C, D, A, X[15] = GET_X_FROM_DATA (M, 15), 22, \
- UINT32_C (0x49b40821));
- }
-
- /* Round 2. */
-
- MD5STEP_R2 (A, B, C, D, X[1], 5, UINT32_C (0xf61e2562));
- MD5STEP_R2 (D, A, B, C, X[6], 9, UINT32_C (0xc040b340));
- MD5STEP_R2 (C, D, A, B, X[11], 14, UINT32_C (0x265e5a51));
- MD5STEP_R2 (B, C, D, A, X[0], 20, UINT32_C (0xe9b6c7aa));
-
- MD5STEP_R2 (A, B, C, D, X[5], 5, UINT32_C (0xd62f105d));
- MD5STEP_R2 (D, A, B, C, X[10], 9, UINT32_C (0x02441453));
- MD5STEP_R2 (C, D, A, B, X[15], 14, UINT32_C (0xd8a1e681));
- MD5STEP_R2 (B, C, D, A, X[4], 20, UINT32_C (0xe7d3fbc8));
-
- MD5STEP_R2 (A, B, C, D, X[9], 5, UINT32_C (0x21e1cde6));
- MD5STEP_R2 (D, A, B, C, X[14], 9, UINT32_C (0xc33707d6));
- MD5STEP_R2 (C, D, A, B, X[3], 14, UINT32_C (0xf4d50d87));
- MD5STEP_R2 (B, C, D, A, X[8], 20, UINT32_C (0x455a14ed));
-
- MD5STEP_R2 (A, B, C, D, X[13], 5, UINT32_C (0xa9e3e905));
- MD5STEP_R2 (D, A, B, C, X[2], 9, UINT32_C (0xfcefa3f8));
- MD5STEP_R2 (C, D, A, B, X[7], 14, UINT32_C (0x676f02d9));
- MD5STEP_R2 (B, C, D, A, X[12], 20, UINT32_C (0x8d2a4c8a));
-
- /* Round 3. */
-
- MD5STEP_R3 (A, B, C, D, X[5], 4, UINT32_C (0xfffa3942));
- MD5STEP_R3 (D, A, B, C, X[8], 11, UINT32_C (0x8771f681));
- MD5STEP_R3 (C, D, A, B, X[11], 16, UINT32_C (0x6d9d6122));
- MD5STEP_R3 (B, C, D, A, X[14], 23, UINT32_C (0xfde5380c));
-
- MD5STEP_R3 (A, B, C, D, X[1], 4, UINT32_C (0xa4beea44));
- MD5STEP_R3 (D, A, B, C, X[4], 11, UINT32_C (0x4bdecfa9));
- MD5STEP_R3 (C, D, A, B, X[7], 16, UINT32_C (0xf6bb4b60));
- MD5STEP_R3 (B, C, D, A, X[10], 23, UINT32_C (0xbebfbc70));
-
- MD5STEP_R3 (A, B, C, D, X[13], 4, UINT32_C (0x289b7ec6));
- MD5STEP_R3 (D, A, B, C, X[0], 11, UINT32_C (0xeaa127fa));
- MD5STEP_R3 (C, D, A, B, X[3], 16, UINT32_C (0xd4ef3085));
- MD5STEP_R3 (B, C, D, A, X[6], 23, UINT32_C (0x04881d05));
-
- MD5STEP_R3 (A, B, C, D, X[9], 4, UINT32_C (0xd9d4d039));
- MD5STEP_R3 (D, A, B, C, X[12], 11, UINT32_C (0xe6db99e5));
- MD5STEP_R3 (C, D, A, B, X[15], 16, UINT32_C (0x1fa27cf8));
- MD5STEP_R3 (B, C, D, A, X[2], 23, UINT32_C (0xc4ac5665));
-
- /* Round 4. */
-
- MD5STEP_R4 (A, B, C, D, X[0], 6, UINT32_C (0xf4292244));
- MD5STEP_R4 (D, A, B, C, X[7], 10, UINT32_C (0x432aff97));
- MD5STEP_R4 (C, D, A, B, X[14], 15, UINT32_C (0xab9423a7));
- MD5STEP_R4 (B, C, D, A, X[5], 21, UINT32_C (0xfc93a039));
-
- MD5STEP_R4 (A, B, C, D, X[12], 6, UINT32_C (0x655b59c3));
- MD5STEP_R4 (D, A, B, C, X[3], 10, UINT32_C (0x8f0ccc92));
- MD5STEP_R4 (C, D, A, B, X[10], 15, UINT32_C (0xffeff47d));
- MD5STEP_R4 (B, C, D, A, X[1], 21, UINT32_C (0x85845dd1));
-
- MD5STEP_R4 (A, B, C, D, X[8], 6, UINT32_C (0x6fa87e4f));
- MD5STEP_R4 (D, A, B, C, X[15], 10, UINT32_C (0xfe2ce6e0));
- MD5STEP_R4 (C, D, A, B, X[6], 15, UINT32_C (0xa3014314));
- MD5STEP_R4 (B, C, D, A, X[13], 21, UINT32_C (0x4e0811a1));
-
- MD5STEP_R4 (A, B, C, D, X[4], 6, UINT32_C (0xf7537e82));
- MD5STEP_R4 (D, A, B, C, X[11], 10, UINT32_C (0xbd3af235));
- MD5STEP_R4 (C, D, A, B, X[2], 15, UINT32_C (0x2ad7d2bb));
- MD5STEP_R4 (B, C, D, A, X[9], 21, UINT32_C (0xeb86d391));
-#else /* MHD_FAVOR_SMALL_CODE */
- if (1)
- {
- static const uint32_t T[64] =
- { UINT32_C (0xd76aa478), UINT32_C (0xe8c7b756), UINT32_C (0x242070db),
- UINT32_C (0xc1bdceee), UINT32_C (0xf57c0faf), UINT32_C (0x4787c62a),
- UINT32_C (0xa8304613), UINT32_C (0xfd469501), UINT32_C (0x698098d8),
- UINT32_C (0x8b44f7af), UINT32_C (0xffff5bb1), UINT32_C (0x895cd7be),
- UINT32_C (0x6b901122), UINT32_C (0xfd987193), UINT32_C (0xa679438e),
- UINT32_C (0x49b40821), UINT32_C (0xf61e2562), UINT32_C (0xc040b340),
- UINT32_C (0x265e5a51), UINT32_C (0xe9b6c7aa), UINT32_C (0xd62f105d),
- UINT32_C (0x02441453), UINT32_C (0xd8a1e681), UINT32_C (0xe7d3fbc8),
- UINT32_C (0x21e1cde6), UINT32_C (0xc33707d6), UINT32_C (0xf4d50d87),
- UINT32_C (0x455a14ed), UINT32_C (0xa9e3e905), UINT32_C (0xfcefa3f8),
- UINT32_C (0x676f02d9), UINT32_C (0x8d2a4c8a), UINT32_C (0xfffa3942),
- UINT32_C (0x8771f681), UINT32_C (0x6d9d6122), UINT32_C (0xfde5380c),
- UINT32_C (0xa4beea44), UINT32_C (0x4bdecfa9), UINT32_C (0xf6bb4b60),
- UINT32_C (0xbebfbc70), UINT32_C (0x289b7ec6), UINT32_C (0xeaa127fa),
- UINT32_C (0xd4ef3085), UINT32_C (0x04881d05), UINT32_C (0xd9d4d039),
- UINT32_C (0xe6db99e5), UINT32_C (0x1fa27cf8), UINT32_C (0xc4ac5665),
- UINT32_C (0xf4292244), UINT32_C (0x432aff97), UINT32_C (0xab9423a7),
- UINT32_C (0xfc93a039), UINT32_C (0x655b59c3), UINT32_C (0x8f0ccc92),
- UINT32_C (0xffeff47d), UINT32_C (0x85845dd1), UINT32_C (0x6fa87e4f),
- UINT32_C (0xfe2ce6e0), UINT32_C (0xa3014314), UINT32_C (0x4e0811a1),
- UINT32_C (0xf7537e82), UINT32_C (0xbd3af235), UINT32_C (0x2ad7d2bb),
- UINT32_C (0xeb86d391) };
- unsigned int i; /**< Zero-based index */
-
- /* Round 1. */
-
- i = 0;
- do
- {
- /* The input data is loaded in correct (little-endian) format before
- calculations on each step. */
- MD5STEP_R1 (A, B, C, D, X[i] = GET_X_FROM_DATA (M, i), 7, T[i]);
- ++i;
- MD5STEP_R1 (D, A, B, C, X[i] = GET_X_FROM_DATA (M, i), 12, T[i]);
- ++i;
- MD5STEP_R1 (C, D, A, B, X[i] = GET_X_FROM_DATA (M, i), 17, T[i]);
- ++i;
- MD5STEP_R1 (B, C, D, A, X[i] = GET_X_FROM_DATA (M, i), 22, T[i]);
- ++i;
- } while (i < 16);
-
- /* Round 2. */
-
- do
- {
- const unsigned int idx_add = i;
- MD5STEP_R2 (A, B, C, D, X[(1U + idx_add) & 15U], 5, T[i]);
- ++i;
- MD5STEP_R2 (D, A, B, C, X[(6U + idx_add) & 15U], 9, T[i]);
- ++i;
- MD5STEP_R2 (C, D, A, B, X[(11U + idx_add) & 15U], 14, T[i]);
- ++i;
- MD5STEP_R2 (B, C, D, A, X[(0U + idx_add) & 15U], 20, T[i]);
- ++i;
- } while (i < 32);
-
- /* Round 3. */
-
- do
- {
- const unsigned int idx_add = i;
- MD5STEP_R3 (A, B, C, D, X[(5U + 64U - idx_add) & 15U], 4, T[i]);
- ++i;
- MD5STEP_R3 (D, A, B, C, X[(8U + 64U - idx_add) & 15U], 11, T[i]);
- ++i;
- MD5STEP_R3 (C, D, A, B, X[(11U + 64U - idx_add) & 15U], 16, T[i]);
- ++i;
- MD5STEP_R3 (B, C, D, A, X[(14U + 64U - idx_add) & 15U], 23, T[i]);
- ++i;
- } while (i < 48);
-
- /* Round 4. */
-
- do
- {
- const unsigned int idx_add = i;
- MD5STEP_R4 (A, B, C, D, X[(0U + 64U - idx_add) & 15U], 6, T[i]);
- ++i;
- MD5STEP_R4 (D, A, B, C, X[(7U + 64U - idx_add) & 15U], 10, T[i]);
- ++i;
- MD5STEP_R4 (C, D, A, B, X[(14U + 64U - idx_add) & 15U], 15, T[i]);
- ++i;
- MD5STEP_R4 (B, C, D, A, X[(5U + 64U - idx_add) & 15U], 21, T[i]);
- ++i;
- } while (i < 64);
- }
-#endif /* MHD_FAVOR_SMALL_CODE */
-
- /* Finally increment and store working variables.
- See RFC 1321, end of Clause 3.4 (step 4). */
-
- H[0] += A;
- H[1] += B;
- H[2] += C;
- H[3] += D;
-}
-
-
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
-MHD_FN_PAR_IN_SIZE_ (3, 2) void
-mhd_MD5_update (struct mhd_Md5CtxInt *restrict ctx,
- size_t size,
- const uint8_t *restrict data)
-{
- unsigned int bytes_have; /**< Number of bytes in the context buffer */
-
- mhd_assert (0 != size);
-
- /* Note: (count & (mhd_MD5_BLOCK_SIZE-1))
- equals (count % mhd_MD5_BLOCK_SIZE) for this block size. */
- bytes_have = (unsigned int)(ctx->count & (mhd_MD5_BLOCK_SIZE - 1));
- ctx->count += size;
-
- if (0 != bytes_have)
- {
- unsigned int bytes_left = mhd_MD5_BLOCK_SIZE - bytes_have;
- if (size >= bytes_left)
- { /* Combine new data with data in the buffer and
- process the full block. */
- memcpy (((uint8_t *)ctx->buffer) + bytes_have,
- data,
- bytes_left);
- data += bytes_left;
- size -= bytes_left;
- md5_transform (ctx->H, ctx->buffer);
- bytes_have = 0;
- }
- }
-
- while (mhd_MD5_BLOCK_SIZE <= size)
- { /* Process any full blocks of new data directly,
- without copying to the buffer. */
- md5_transform (ctx->H, data);
- data += mhd_MD5_BLOCK_SIZE;
- size -= mhd_MD5_BLOCK_SIZE;
- }
-
- if (0 != size)
- { /* Copy incomplete block of new data (if any)
- to the buffer. */
- memcpy (((uint8_t *)ctx->buffer) + bytes_have, data, size);
- }
-}
-
-
-/**
- * Size of "length" insertion in bits.
- * See RFC 1321, end of Clause 3.2 (step 2).
- */
-#define MD5_SIZE_OF_LEN_ADD_BITS 64
-
-/**
- * Size of "length" insertion in bytes.
- */
-#define MD5_SIZE_OF_LEN_ADD (MD5_SIZE_OF_LEN_ADD_BITS / 8)
-
-MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
-MHD_FN_PAR_OUT_ (2) void
-mhd_MD5_finish (struct mhd_Md5CtxInt *restrict ctx,
- uint8_t digest[mhd_MD5_DIGEST_SIZE])
-{
- uint64_t num_bits; /**< Number of processed bits */
- unsigned int bytes_have; /**< Number of bytes in the context buffer */
-
- /* Memorise the number of processed bits.
- The padding and other data added here during the postprocessing must
- not change the amount of hashed data. */
- num_bits = ctx->count << 3;
-
- /* Note: (count & (mhd_MD5_BLOCK_SIZE-1))
- equals (count % mhd_MD5_BLOCK_SIZE) for this block size. */
- bytes_have = (unsigned int)(ctx->count & (mhd_MD5_BLOCK_SIZE - 1));
-
- /* Input data must be padded with a single bit "1", then with zeros and
- the finally the length of data in bits must be added as the final bytes
- of the last block.
- See RFC 1321, Clauses 3.1 and 3.2 (steps 1 and 2). */
- /* Data is always processed in form of bytes (not by individual bits),
- therefore position of the first padding bit in byte is always
- predefined (0x80). */
- /* Buffer always have space for one byte at least (as full buffers are
- processed immediately). */
- ((uint8_t *)ctx->buffer)[bytes_have++] = 0x80;
-
- if (mhd_MD5_BLOCK_SIZE - bytes_have < MD5_SIZE_OF_LEN_ADD)
- { /* No space in the current block to put the total length of message.
- Pad the current block with zeros and process it. */
- if (bytes_have < mhd_MD5_BLOCK_SIZE)
- memset (((uint8_t *)ctx->buffer) + bytes_have, 0,
- mhd_MD5_BLOCK_SIZE - bytes_have);
- /* Process the full block. */
- md5_transform (ctx->H, ctx->buffer);
- /* Start the new block. */
- bytes_have = 0;
- }
-
- /* Pad the rest of the buffer with zeros. */
- memset (((uint8_t *)ctx->buffer) + bytes_have, 0,
- mhd_MD5_BLOCK_SIZE - MD5_SIZE_OF_LEN_ADD - bytes_have);
- /* Put the number of bits in processed data as little-endian value.
- See RFC 1321, clauses 2 and 3.2 (step 2). */
- mhd_PUT_64BIT_LE_UNALIGN (ctx->buffer + mhd_MD5_BLOCK_SIZE_WORDS - 2,
- num_bits);
- /* Process the full final block. */
- md5_transform (ctx->H, ctx->buffer);
-
- /* Put in LE mode the hash as the final digest.
- See RFC 1321, clauses 2 and 3.5 (step 5). */
- if (1)
- {
- bool use_tmp_buf_to_align_result;
-
-#if defined(mhd_PUT_32BIT_LE_UNALIGNED)
- use_tmp_buf_to_align_result = false;
-#elif defined(MHD_FAVOR_SMALL_CODE)
- use_tmp_buf_to_align_result = true; /* smaller code: eliminated branch below */
-#else
- use_tmp_buf_to_align_result =
- (0 != ((uintptr_t)digest) % mhd_UINT32_ALIGN);
-#endif
- if (use_tmp_buf_to_align_result)
- {
- /* If storing of the final result requires aligned address and
- the destination address is not aligned or compact code is used,
- store the final digest in aligned temporary buffer first, then
- copy it to the destination. */
- uint32_t alig_dgst[mhd_MD5_DIGEST_SIZE_WORDS];
- mhd_PUT_32BIT_LE (alig_dgst + 0, ctx->H[0]);
- mhd_PUT_32BIT_LE (alig_dgst + 1, ctx->H[1]);
- mhd_PUT_32BIT_LE (alig_dgst + 2, ctx->H[2]);
- mhd_PUT_32BIT_LE (alig_dgst + 3, ctx->H[3]);
- /* Copy result to the unaligned destination address. */
- memcpy (digest, alig_dgst, mhd_MD5_DIGEST_SIZE);
- }
- else
- {
- /* Use cast to (void*) here to mute compiler alignment warnings.
- * Compilers are not smart enough to see that alignment has been checked. */
- mhd_PUT_32BIT_LE ((void *)(digest + 0 * mhd_MD5_BYTES_IN_WORD), \
- ctx->H[0]);
- mhd_PUT_32BIT_LE ((void *)(digest + 1 * mhd_MD5_BYTES_IN_WORD), \
- ctx->H[1]);
- mhd_PUT_32BIT_LE ((void *)(digest + 2 * mhd_MD5_BYTES_IN_WORD), \
- ctx->H[2]);
- mhd_PUT_32BIT_LE ((void *)(digest + 3 * mhd_MD5_BYTES_IN_WORD), \
- ctx->H[3]);
- }
- }
-
- /* Erase potentially sensitive data. */
- memset (ctx, 0, sizeof(struct mhd_Md5CtxInt));
-}
-
-
-mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE
diff --git a/src/mhd2/md5_int.h b/src/mhd2/md5_int.h
@@ -1,147 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
-/*
- This file is part of GNU libmicrohttpd.
- Copyright (C) 2022-2024 Evgeny Grin (Karlson2k)
-
- GNU libmicrohttpd is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- GNU libmicrohttpd is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- Alternatively, you can redistribute GNU libmicrohttpd and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version, together
- with the eCos exception, as follows:
-
- As a special exception, if other files instantiate templates or
- use macros or inline functions from this file, or you compile this
- file and link it with other works to produce a work based on this
- file, this file does not by itself cause the resulting work to be
- covered by the GNU General Public License. However the source code
- for this file must still be made available in accordance with
- section (3) of the GNU General Public License v2.
-
- This exception does not invalidate any other reasons why a work
- based on this file might be covered by the GNU General Public
- License.
-
- You should have received copies of the GNU Lesser General Public
- License and the GNU General Public License along with this library;
- if not, see <https://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file src/mhd2/md5_int.h
- * @brief Calculation of MD5 digest
- * @author Karlson2k (Evgeny Grin)
- */
-
-#ifndef MHD_MD5_INT_H
-#define MHD_MD5_INT_H 1
-
-#include "mhd_sys_options.h"
-
-#include "sys_base_types.h"
-
-/**
- * Number of bits in single MD5 word.
- */
-#define mhd_MD5_WORD_SIZE_BITS (32)
-
-/**
- * Number of bytes in single MD5 word.
- */
-#define mhd_MD5_BYTES_IN_WORD (mhd_MD5_WORD_SIZE_BITS / 8)
-
-/**
- * Hash is kept internally as four 32-bit words.
- * This is intermediate hash size, used during computing the final digest.
- */
-#define mhd_MD5_HASH_SIZE_WORDS (4)
-
-/**
- * Size of MD5 resulting digest in bytes.
- * This is the final digest size, not intermediate hash.
- */
-#define mhd_MD5_DIGEST_SIZE_WORDS mhd_MD5_HASH_SIZE_WORDS
-
-/**
- * Size of MD5 resulting digest in bytes
- * This is the final digest size, not intermediate hash.
- */
-#define mhd_MD5_DIGEST_SIZE (mhd_MD5_DIGEST_SIZE_WORDS * mhd_MD5_BYTES_IN_WORD)
-
-/**
- * Size of MD5 single processing block in bits.
- */
-#define mhd_MD5_BLOCK_SIZE_BITS 512
-
-/**
- * Size of MD5 single processing block in bytes.
- */
-#define mhd_MD5_BLOCK_SIZE (mhd_MD5_BLOCK_SIZE_BITS / 8)
-
-/**
- * Size of MD5 single processing block in words.
- */
-#define mhd_MD5_BLOCK_SIZE_WORDS \
- (mhd_MD5_BLOCK_SIZE_BITS / mhd_MD5_WORD_SIZE_BITS)
-
-
-/**
- * MD5 calculation context
- */
-struct mhd_Md5CtxInt
-{
- uint32_t H[mhd_MD5_HASH_SIZE_WORDS]; /**< Intermediate hash value / digest at end of calculation */
- uint32_t buffer[mhd_MD5_BLOCK_SIZE_WORDS]; /**< MD5 input data buffer */
- uint64_t count; /**< number of bytes, mod 2^64 */
-};
-
-/**
- * Initialise structure for MD5 calculation.
- *
- * @param ctx the calculation context
- */
-MHD_INTERNAL void
-mhd_MD5_init (struct mhd_Md5CtxInt *ctx)
-MHD_FN_PAR_NONNULL_ALL_;
-
-
-/**
- * MD5 process portion of bytes.
- *
- * @param ctx the calculation context
- * @param size number of bytes in @a data
- * @param data bytes to add to hash
- */
-MHD_INTERNAL void
-mhd_MD5_update (struct mhd_Md5CtxInt *restrict ctx,
- size_t size,
- const uint8_t *restrict data)
-MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3, 2);
-
-
-/**
- * Finalise MD5 calculation, return digest.
- *
- * @param ctx the calculation context
- * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
- */
-MHD_INTERNAL void
-mhd_MD5_finish (struct mhd_Md5CtxInt *restrict ctx,
- uint8_t digest[mhd_MD5_DIGEST_SIZE])
-MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (2);
-
-/**
- * Indicates that function mhd_MD5_finish() (without context reset) is available
- */
-#define mhd_MD5_HAS_FINISH 1
-
-#endif /* MHD_MD5_INT_H */
diff --git a/src/mhd2/md5_mbedtls.c b/src/mhd2/md5_mbedtls.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2026 Evgeny Grin (Karlson2k)
+ Copyright (C) 2025 Christian Grothoff
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/md5_mbedtls.c
+ * @brief Wrapper for MD5 calculation performed by mbedTLS library
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ */
+
+#include "mhd_sys_options.h"
+
+#include "mhd_assert.h"
+
+#include "md5_mbedtls.h"
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1) void
+mhd_MD5_mtls_init (struct mhd_Md5CtxMtls *ctx)
+{
+ mbedtls_md5_init (&(ctx->mbed_ctx));
+ ctx->ext_error = (0 != mbedtls_md5_starts (&(ctx->mbed_ctx)));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) void
+mhd_MD5_mtls_reset (struct mhd_Md5CtxMtls *ctx)
+{
+ if (ctx->ext_error)
+ return;
+
+ ctx->ext_error = (0 != mbedtls_md5_starts (&(ctx->mbed_ctx)));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_IN_SIZE_ (3, 2) void
+mhd_MD5_mtls_update (struct mhd_Md5CtxMtls *restrict ctx,
+ size_t size,
+ const void *restrict data)
+{
+#ifndef MHD_UNIT_TESTING
+ mhd_assert (0 != size);
+#endif
+
+ if (ctx->ext_error)
+ return;
+
+ ctx->ext_error = (0 != mbedtls_md5_update (&(ctx->mbed_ctx),
+ (const unsigned char *)data,
+ size));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_OUT_ (2) void
+mhd_MD5_mtls_finish (
+ struct mhd_Md5CtxMtls *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+{
+ if (ctx->ext_error)
+ return;
+
+ ctx->ext_error = (0 != mbedtls_md5_finish (&(ctx->mbed_ctx),
+ (unsigned char *)digest));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) void
+mhd_MD5_mtls_deinit (struct mhd_Md5CtxMtls *ctx)
+{
+ mbedtls_md5_free (&(ctx->mbed_ctx));
+}
diff --git a/src/mhd2/md5_mbedtls.h b/src/mhd2/md5_mbedtls.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+/**
+ * @file src/mhd2/md5_mbedtls.h
+ * @brief Wrapper declarations for MD5 calculation performed by mbedTLS backend
+ * @author Karlson2k (Evgeny Grin)
+ */
+#ifndef MHD_MD5_MBEDTLS_H
+#define MHD_MD5_MBEDTLS_H 1
+
+#include "mhd_sys_options.h"
+
+#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+/* MbedTLS header is small in size and scope, it is directly included here */
+#include <mbedtls/md5.h>
+
+#ifndef mhd_MD5_DIGEST_SIZE
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not the intermediate hash.
+ */
+# define mhd_MD5_DIGEST_SIZE (16)
+#endif
+
+/**
+ * MD5 calculation context
+ */
+struct mhd_Md5CtxMtls
+{
+ struct mbedtls_md5_context mbed_ctx; /**< Hash calculation handle */
+ bool ext_error; /**< 'true' if the hashing backend has reported an error */
+};
+
+/**
+ * Indicates whether struct mhd_Md5CtxMtls has an 'ext_error' member.
+ *
+ * Set to '1' when the structure has an 'ext_error' member.
+ */
+#define mhd_MD5_MTLS_EXT_ERROR_FLAG 1
+
+/**
+ * Initialise the context for MD5 calculation.
+ *
+ * This function must not be called more than once for @a ctx without an
+ * intervening #mhd_MD5_mtls_deinit().
+ *
+ * Whether or not an error is reported, #mhd_MD5_mtls_deinit() must be
+ * called for @a ctx once this function has returned.
+ *
+ * The error state in @a ctx is set according to the result: cleared on
+ * success, set on failure.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_mtls_init (struct mhd_Md5CtxMtls *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1);
+
+
+/**
+ * Add a portion of data to the MD5 calculation.
+ *
+ * If @a ctx already has a recorded error, this function does nothing.
+ * Otherwise, if the operation fails, the error is recorded in @a ctx.
+ *
+ * @param ctx the calculation context
+ * @param size number of bytes in @a data, must not be 0
+ * @param data bytes to add to hash
+ */
+MHD_INTERNAL void
+mhd_MD5_mtls_update (struct mhd_Md5CtxMtls *restrict ctx,
+ size_t size,
+ const void *restrict data)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_IN_SIZE_ (3, 2);
+
+/**
+ * Finalise the MD5 calculation and return the digest.
+ *
+ * If @a ctx already has a recorded error, this function does nothing.
+ * Otherwise, if the operation fails, the error is recorded in @a ctx.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+MHD_INTERNAL void
+mhd_MD5_mtls_finish (
+ struct mhd_Md5CtxMtls *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_OUT_ (2);
+
+/**
+ * Reset the context for a new MD5 calculation.
+ *
+ * This function may be called only after #mhd_MD5_mtls_finish(). If the context
+ * is subsequently reused for a new calculation, this function must be called
+ * before starting that calculation.
+ *
+ * If @a ctx already has a recorded error, this function does nothing and the
+ * error is preserved. Otherwise, if the operation fails, the error is recorded
+ * in @a ctx.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_mtls_reset (struct mhd_Md5CtxMtls *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+/**
+ * Deinitialise the MD5 calculation context.
+ *
+ * After calling this function, @a ctx can be reinitialised with
+ * #mhd_MD5_mtls_init().
+ *
+ * The recorded error state in @a ctx is preserved.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_mtls_deinit (struct mhd_Md5CtxMtls *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+/**
+ * Indicates whether #mhd_MD5_mtls_deinit() is a real function or a no-op.
+ *
+ * Set to '0' as #mhd_MD5_mtls_deinit() is a real function.
+ */
+#define mhd_MD5_MTLS_DEINIT_NOOP_FLAG 0
+
+
+#endif /* MHD_MD5_MBEDTLS_H */
diff --git a/src/mhd2/md5_openssl.c b/src/mhd2/md5_openssl.c
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2026 Evgeny Grin (Karlson2k)
+ Copyright (C) 2025 Christian Grothoff
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/mhd2/md5_openssl.c
+ * @brief Wrapper for MD5 calculation performed by OpenSSL backend
+ * @author Karlson2k (Evgeny Grin)
+ * @author Christian Grothoff
+ */
+
+#include "mhd_sys_options.h"
+
+#include "mhd_assert.h"
+
+#include <openssl/evp.h>
+
+#include "md5_openssl.h"
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1) void
+mhd_MD5_ossl_init (struct mhd_Md5CtxOssl *ctx)
+{
+ ctx->ossl_ctx = EVP_MD_CTX_new ();
+ ctx->ext_error = (NULL == ctx->ossl_ctx);
+
+ mhd_MD5_ossl_reset (ctx);
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) void
+mhd_MD5_ossl_reset (struct mhd_Md5CtxOssl *ctx)
+{
+ if (ctx->ext_error)
+ return;
+
+ mhd_assert (NULL != ctx->ossl_ctx);
+
+ ctx->ext_error = (0 == EVP_DigestInit_ex (ctx->ossl_ctx,
+ EVP_md5 (),
+ NULL));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_IN_SIZE_ (3, 2) void
+mhd_MD5_ossl_update (struct mhd_Md5CtxOssl *restrict ctx,
+ size_t size,
+ const void *restrict data)
+{
+#ifndef MHD_UNIT_TESTING
+ mhd_assert (0 != size);
+#endif
+
+ if (ctx->ext_error)
+ return;
+
+ mhd_assert (NULL != ctx->ossl_ctx);
+
+ ctx->ext_error = (0 == EVP_DigestUpdate (ctx->ossl_ctx,
+ data,
+ size));
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1)
+MHD_FN_PAR_OUT_ (2) void
+mhd_MD5_ossl_finish (
+ struct mhd_Md5CtxOssl *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+{
+ if (!ctx->ext_error)
+ {
+#ifndef NDEBUG
+ unsigned int len;
+
+ mhd_assert (NULL != ctx->ossl_ctx);
+
+ ctx->ext_error = (0 == EVP_DigestFinal_ex (ctx->ossl_ctx,
+ digest,
+ &len));
+ mhd_assert ((ctx->ext_error) || (mhd_MD5_DIGEST_SIZE == len));
+#else
+ ctx->ext_error = (0 == EVP_DigestFinal_ex (ctx->ossl_ctx,
+ digest,
+ NULL));
+#endif
+ }
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) void
+mhd_MD5_ossl_deinit (struct mhd_Md5CtxOssl *ctx)
+{
+ EVP_MD_CTX_free (ctx->ossl_ctx);
+ ctx->ossl_ctx = NULL;
+}
diff --git a/src/mhd2/md5_openssl.h b/src/mhd2/md5_openssl.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
+
+ GNU libmicrohttpd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ GNU libmicrohttpd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+/**
+ * @file src/mhd2/md5_openssl.h
+ * @brief Wrapper declarations for MD5 calculation performed by OpenSSL backend
+ * @author Karlson2k (Evgeny Grin)
+ */
+#ifndef MHD_MD5_OPENSSL_H
+#define MHD_MD5_OPENSSL_H 1
+
+#include "mhd_sys_options.h"
+
+#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#ifndef mhd_MD5_DIGEST_SIZE
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not the intermediate hash.
+ */
+# define mhd_MD5_DIGEST_SIZE (16)
+#endif
+
+/* Forward declaration for OpenSSL struct, to avoid including large header */
+struct evp_md_ctx_st;
+
+/**
+ * MD5 calculation context
+ */
+struct mhd_Md5CtxOssl
+{
+ struct evp_md_ctx_st *ossl_ctx; /**< Hash calculation handle */
+ bool ext_error; /**< 'true' if the hashing backend has reported an error */
+};
+
+/**
+ * Indicates whether struct mhd_Md5CtxOssl has an 'ext_error' member.
+ *
+ * Set to '1' when the structure has an 'ext_error' member.
+ */
+#define mhd_MD5_OSSL_EXT_ERROR_FLAG 1
+
+/**
+ * Initialise the context for MD5 calculation.
+ *
+ * This function must not be called more than once for @a ctx without an
+ * intervening #mhd_MD5_ossl_deinit().
+ *
+ * Whether or not an error is reported, #mhd_MD5_ossl_deinit() must be
+ * called for @a ctx once this function has returned.
+ *
+ * The error state in @a ctx is set according to the result: cleared on
+ * success, set on failure.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_ossl_init (struct mhd_Md5CtxOssl *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (1);
+
+/**
+ * Add a portion of data to the MD5 calculation.
+ *
+ * If @a ctx already has a recorded error, this function does nothing.
+ * Otherwise, if the operation fails, the error is recorded in @a ctx.
+ *
+ * @param ctx the calculation context
+ * @param size number of bytes in @a data, must not be 0
+ * @param data bytes to add to hash
+ */
+MHD_INTERNAL void
+mhd_MD5_ossl_update (struct mhd_Md5CtxOssl *restrict ctx,
+ size_t size,
+ const void *restrict data)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_IN_SIZE_ (3, 2);
+
+/**
+ * Finalise the MD5 calculation and return the digest.
+ *
+ * If @a ctx already has a recorded error, this function does nothing.
+ * Otherwise, if the operation fails, the error is recorded in @a ctx.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+MHD_INTERNAL void
+mhd_MD5_ossl_finish (
+ struct mhd_Md5CtxOssl *restrict ctx,
+ uint8_t digest[MHD_FN_PAR_FIX_ARR_SIZE_ (mhd_MD5_DIGEST_SIZE)])
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_OUT_ (2);
+
+/**
+ * Reset the context for a new MD5 calculation.
+ *
+ * This function may be called only after #mhd_MD5_ossl_finish(). If the context
+ * is subsequently reused for a new calculation, this function must be called
+ * before starting that calculation.
+ *
+ * If @a ctx already has a recorded error, this function does nothing and the
+ * error is preserved. Otherwise, if the operation fails, the error is recorded
+ * in @a ctx.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_ossl_reset (struct mhd_Md5CtxOssl *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+/**
+ * Deinitialise the MD5 calculation context.
+ *
+ * After calling this function, @a ctx can be reinitialised with
+ * #mhd_MD5_ossl_init().
+ *
+ * The recorded error state in @a ctx is preserved.
+ *
+ * @param ctx the calculation context
+ */
+MHD_INTERNAL void
+mhd_MD5_ossl_deinit (struct mhd_Md5CtxOssl *ctx)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+/**
+ * Indicates whether #mhd_MD5_ossl_deinit() is a real function or a no-op.
+ *
+ * Set to '0' as #mhd_MD5_ossl_deinit() is a real function.
+ */
+#define mhd_MD5_OSSL_DEINIT_NOOP_FLAG 0
+
+
+#endif /* MHD_MD5_OPENSSL_H */
diff --git a/src/mhd2/mhd_macro_concat.h b/src/mhd2/mhd_macro_concat.h
@@ -49,6 +49,16 @@
/**
+ * Concatenate two arguments literally
+ */
+#define mhd_MACRO_CONCAT_(a, b) a ## b
+/**
+ * Concatenate two arguments after expansion
+ */
+#define mhd_MACRO_CONCAT(a, b) mhd_MACRO_CONCAT_ (a,b)
+
+
+/**
* Concatenate three arguments literally
*/
#define mhd_MACRO_CONCAT3_(a, b, c) a ## b ## c
diff --git a/src/mhd2/mhd_md5.h b/src/mhd2/mhd_md5.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
/*
This file is part of GNU libmicrohttpd.
- Copyright (C) 2022-2024 Evgeny Grin (Karlson2k)
+ Copyright (C) 2022-2026 Evgeny Grin (Karlson2k)
GNU libmicrohttpd is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -38,7 +38,14 @@
/**
* @file src/mhd2/mhd_md5.h
- * @brief Simple wrapper for selection of built-in/external MD5 implementation
+ * @brief Simple wrapper for selecting the MD5 implementation backend
+ *
+ * Usage: declare a context as 'struct mhd_Md5Ctx', then call mhd_MD5_init(),
+ * mhd_MD5_update() (any number of times) and mhd_MD5_finish() to get the
+ * digest. Reuse the context with mhd_MD5_reset() or release it with
+ * mhd_MD5_deinit(). With some backends an operation can fail; check with
+ * mhd_MD5_has_err().
+ *
* @author Karlson2k (Evgeny Grin)
*/
@@ -51,82 +58,218 @@
# error This file must be used only when MD5 is enabled
#endif
-#ifndef MHD_MD5_EXTR
-# include "md5_int.h"
-#else /* MHD_MD5_EXTR */
-# include "md5_ext.h"
-#endif /* MHD_MD5_EXTR */
+#include "mhd_macro_concat.h"
-#ifndef mhd_MD5_DIGEST_SIZE
+#if defined(MHD_MD5_EXTR_GNUTLS)
+# include "md5_gnutls.h"
+
+/**
+ * The hashing backend identifier for function names
+ */
+# define mhd_MD5_FUNC_NAME_ID gtls
/**
- * Size of MD5 resulting digest in bytes
- * This is the final digest size, not intermediate hash.
+ * The hashing backend identifier for data names
*/
-# define mhd_MD5_DIGEST_SIZE (16)
-#endif /* ! mhd_MD5_DIGEST_SIZE */
+# define mhd_MD5_DATA_NAME_ID Gtls
+/**
+ * The hashing backend identifier for macro names
+ */
+# define mhd_MD5_MACRO_NAME_ID GTLS
+
+#elif defined(MHD_MD5_EXTR_OPENSSL)
+# include "md5_openssl.h"
-#ifndef MHD_MD5_EXTR
/**
- * Universal ctx type mapped for chosen implementation
+ * The hashing backend identifier for function names
+ */
+# define mhd_MD5_FUNC_NAME_ID ossl
+/**
+ * The hashing backend identifier for data names
*/
-# define mhd_Md5Ctx mhd_Md5CtxInt
-#else /* MHD_MD5_EXTR */
+# define mhd_MD5_DATA_NAME_ID Ossl
/**
- * Universal ctx type mapped for chosen implementation
+ * The hashing backend identifier for macro names
*/
-# define mhd_Md5Ctx mhd_Md5CtxExt
-#endif /* MHD_MD5_EXTR */
+# define mhd_MD5_MACRO_NAME_ID OSSL
+
+#elif defined(MHD_MD5_EXTR_MBEDTLS)
+# include "md5_mbedtls.h"
-#ifndef mhd_MD5_HAS_INIT_ONE_TIME
/**
- * Setup and prepare ctx for hash calculation
+ * The hashing backend identifier for function names
+ */
+# define mhd_MD5_FUNC_NAME_ID mtls
+/**
+ * The hashing backend identifier for data names
*/
-# define mhd_MD5_init_one_time(ctx) mhd_MD5_init (ctx)
-#endif /* ! mhd_MD5_HAS_INIT_ONE_TIME */
+# define mhd_MD5_DATA_NAME_ID Mtls
+/**
+ * The hashing backend identifier for macro names
+ */
+# define mhd_MD5_MACRO_NAME_ID MTLS
+#elif !defined(MHD_MD5_EXTR)
+# include "md5_builtin.h"
-#ifndef mhd_MD5_HAS_FINISH_RESET
/**
- * Re-use the same ctx for the new hashing after digest calculated
+ * The hashing backend identifier for function names
*/
-# define mhd_MD5_reset(ctx) mhd_MD5_init (ctx)
+# define mhd_MD5_FUNC_NAME_ID blti
/**
- * Finalise MD5 calculation, return digest, reset hash calculation.
+ * The hashing backend identifier for data names
*/
-# define mhd_MD5_finish_reset(ctx, digest) \
- (mhd_MD5_finish (ctx,digest), mhd_MD5_reset (ctx))
+# define mhd_MD5_DATA_NAME_ID Blti
/**
- * Finalise hash calculation, return digest, de-initialise hash calculation.
+ * The hashing backend identifier for macro names
*/
-# define mhd_MD5_finish_deinit(ctx, digest) \
- (mhd_MD5_finish (ctx,digest), mhd_MD5_deinit (ctx))
-#else /* mhd_MD5_HAS_FINISH_RESET */
+# define mhd_MD5_MACRO_NAME_ID BLTI
+#else
+# error No MD5 implementation enabled
+#endif
+
+#if mhd_MD5_DIGEST_SIZE != 16
+# error Wrong value of mhd_MD5_DIGEST_SIZE
+#endif
+
/**
- * Finalise MD5 calculation, return digest
+ * Form the name of the function specific to the selected hashing backend
*/
-# define mhd_MD5_finish(ctx, digest) mhd_MD5_finish_reset(ctx, digest)
-# define mhd_MD5_reset(ctx) ((void) 0)
+#define mhd_MD5_FUNC(name_suffix) \
+ mhd_MACRO_CONCAT3 (mhd_MD5_,mhd_MD5_FUNC_NAME_ID,name_suffix)
+
/**
- * Finalise hash calculation, return digest, de-initialise hash calculation.
+ * Form the name of the macro specific to the selected hashing backend
*/
-# define mhd_MD5_finish_deinit(ctx, digest) \
- (mhd_MD5_finish_reset (ctx,digest), mhd_MD5_deinit (ctx))
-#endif /* mhd_MD5_HAS_FINISH_RESET */
+#define mhd_MD5_MACRO(name_suffix) \
+ mhd_MACRO_CONCAT3 (mhd_MD5_,mhd_MD5_MACRO_NAME_ID,name_suffix)
-#ifndef mhd_MD5_HAS_DEINIT
-# define mhd_MD5_deinit(ctx) ((void) 0)
-#endif /* HAVE_MD5_DEINIT */
+/**
+ * Struct tag of the calculation context for the selected MD5 backend
+ */
+#define mhd_Md5Ctx mhd_MACRO_CONCAT(mhd_Md5Ctx,mhd_MD5_DATA_NAME_ID)
-#ifdef mhd_MD5_HAS_EXT_ERROR
-# define mhd_MD5_has_err(ctx) (0 != ((ctx)->ext_error))
-#else /* ! mhd_MD5_HAS_EXT_ERROR */
-# define mhd_MD5_has_err(ctx) (((void) (ctx)), ! ! 0)
-#endif /* ! mhd_SHA512_256_HAS_EXT_ERROR */
+#if 0 != mhd_MD5_MACRO (_EXT_ERROR_FLAG)
+/**
+ * Indicates that MD5 hashing or initialisation may result in an error
+ */
+# define mhd_MD5_HAS_EXT_ERROR 1
+/**
+ * 'true' if the hashing backend has reported an error
+ */
+# define mhd_MD5_has_err(ctx) (!!((ctx)->ext_error))
+/**
+ * Get the error number reported by hashing backend (zero if no error)
+ */
+# define mhd_MD5_get_err(ctx) ((int)((ctx)->ext_error))
+#else
+# define mhd_MD5_has_err(ctx) (((void) (ctx)), !!0)
+/**
+ * Get the error number (zero if no error)
+ */
+# define mhd_MD5_get_err(ctx) ((int)(0))
+#endif
+
+/**
+ * Initialise the context for MD5 calculation.
+ *
+ * This function must not be called more than once for @a ctx without an
+ * intervening #mhd_MD5_deinit().
+ *
+ * Whether or not an error is reported, #mhd_MD5_deinit() must be
+ * called for @a ctx once this function has returned.
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()), the error state is
+ * set according to the result: cleared on success, set on failure.
+ *
+ * @param ctx the calculation context
+ */
+#define mhd_MD5_init(ctx) mhd_MD5_FUNC(_init) ((ctx))
+
+/**
+ * Add a portion of data to the MD5 calculation.
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()), this does nothing
+ * if @a ctx already has a recorded error, and records an error on failure.
+ *
+ * @param ctx the calculation context
+ * @param size number of bytes in @a data, must not be 0
+ * @param data bytes to add to hash
+ */
+#define mhd_MD5_update(ctx, size, data) \
+ mhd_MD5_FUNC(_update) ((ctx),(size),(data))
+
+/**
+ * Finalise the MD5 calculation and return the digest.
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()), this does nothing
+ * if @a ctx already has a recorded error, and may record an error on failure.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+#define mhd_MD5_finish(ctx, digest) \
+ mhd_MD5_FUNC(_finish) ((ctx),(digest))
+
+/**
+ * Reset the context for a new MD5 calculation.
+ *
+ * This function may be called only after #mhd_MD5_finish(). If the context is
+ * subsequently reused for a new calculation, this function must be called
+ * before starting that calculation.
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()), this does nothing
+ * if @a ctx already has a recorded error, and may record an error on failure.
+ *
+ * @param ctx the calculation context
+ */
+#define mhd_MD5_reset(ctx) mhd_MD5_FUNC(_reset) ((ctx))
+
+/**
+ * Finalise the MD5 calculation, return the digest and reset the context.
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()): if @a ctx already
+ * has a recorded error, this does nothing and the error is preserved.
+ * Otherwise, an error is recorded in @a ctx if either the finalisation or the
+ * reset fails. A recorded error is never cleared by this macro.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+#define mhd_MD5_finish_reset(ctx, digest) \
+ (mhd_MD5_finish((ctx),(digest)), mhd_MD5_reset((ctx)))
+
+/**
+ * Deinitialise the MD5 calculation context.
+ *
+ * After calling this function, @a ctx can be reinitialised with
+ * #mhd_MD5_init().
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()), the recorded error
+ * state is preserved.
+ *
+ * @param ctx the calculation context
+ */
+#define mhd_MD5_deinit(ctx) mhd_MD5_FUNC(_deinit) ((ctx))
-/* Sanity checks */
+/**
+ * Finalise the MD5 calculation, return the digest and deinitialise the context.
+ *
+ * For backends that track errors (see #mhd_MD5_has_err()): if @a ctx already
+ * has a recorded error, the error is preserved. Otherwise, an error is
+ * recorded in @a ctx if the finalisation fails.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #mhd_MD5_DIGEST_SIZE bytes
+ */
+#define mhd_MD5_finish_deinit(ctx, digest) \
+ (mhd_MD5_finish((ctx),(digest)), mhd_MD5_deinit((ctx)))
+
+#if 0 == mhd_MD5_MACRO (_DEINIT_NOOP_FLAG)
+/**
+ * Indicates that #mhd_MD5_deinit() is a real function that must be called.
+ */
+# define mhd_MD5_HAS_DEINIT
+#endif
-#if !defined(mhd_MD5_HAS_FINISH_RESET) && !defined(mhd_MD5_HAS_FINISH)
-# error Required at least one of mhd_MD5_finish_reset(), mhd_MD5_finish()
-#endif /* ! mhd_MD5_HAS_FINISH_RESET && ! mhd_MD5_HAS_FINISH */
#endif /* MHD_MD5_H */
diff --git a/src/tests/unit/Makefile.am b/src/tests/unit/Makefile.am
@@ -112,7 +112,24 @@ unit_hpack_tables_static_SOURCES = $(unit_hpack_tables_dynamic_SOURCES)
unit_hpack_tables_combined_SOURCES = $(unit_hpack_tables_dynamic_SOURCES)
-unit_md5_SOURCES = unit_md5.c
+unit_md5_SOURCES = \
+ unit_md5.c \
+ $(srcdir)/../../mhd2/mhd_md5.h \
+ $(srcdir)/../../mhd2/md5_builtin.c $(srcdir)/../../mhd2/md5_builtin.h
+
+if MHD_SUPPORT_GNUTLS
+ unit_md5_SOURCES += \
+ $(srcdir)/../../mhd2/md5_gnutls.c $(srcdir)/../../mhd2/md5_gnutls.h
+endif
+if MHD_SUPPORT_OPENSSL
+ unit_md5_SOURCES += \
+ $(srcdir)/../../mhd2/md5_openssl.c $(srcdir)/../../mhd2/md5_openssl.h
+endif
+if MHD_SUPPORT_MBEDTLS
+ unit_md5_SOURCES += \
+ $(srcdir)/../../mhd2/md5_mbedtls.c $(srcdir)/../../mhd2/md5_mbedtls.h
+endif
+
unit_sha256_SOURCES = unit_sha256.c
diff --git a/src/tests/unit/unit_md5.c b/src/tests/unit/unit_md5.c
@@ -48,20 +48,9 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
-#include <stdbool.h>
#include "mhdt_has_param.h"
-#if defined MHD_MD5_EXTR_OPENSSL
-# include "../mhd2/md5_ext_openssl.c"
-#elif defined MHD_MD5_EXTR_GNUTLS
-# include "../mhd2/md5_ext_gnutls.c"
-#elif defined MHD_MD5_EXTR_MBEDTLS
-# include "../mhd2/md5_ext_mbedtls.c"
-#else
-# include "../mhd2/md5_int.c"
-#endif
-
#include "../mhd2/mhd_md5.h"
#define MD5_DIGEST_STRING_SIZE (mhd_MD5_DIGEST_SIZE * 2 + 1)
@@ -72,9 +61,6 @@
static int verbose;
-/* Define to 1 if libmicrohttpd is compiled with MD5 hashing by OpenSSL. */
-/* #undef MHD_MD5_EXTR_OPENSSL */
-
/* Helper function to convert hex string to binary */
static size_t
hex2bin (const char *hex,
@@ -129,10 +115,10 @@ check_result (const char *test_name,
const uint8_t calculated[mhd_MD5_DIGEST_SIZE],
const uint8_t expected[mhd_MD5_DIGEST_SIZE])
{
- bool failed = (0 !=
- memcmp (calculated,
- expected,
- mhd_MD5_DIGEST_SIZE));
+ int failed = (0 !=
+ memcmp (calculated,
+ expected,
+ mhd_MD5_DIGEST_SIZE));
check_num++; /* Print 1-based numbers */
if (failed)
@@ -247,7 +233,7 @@ test1_str (void)
unsigned int num_failed = 0;
struct mhd_Md5Ctx ctx;
- mhd_MD5_init_one_time (&ctx);
+ mhd_MD5_init (&ctx);
for (i = 0; i < units1_num; i++)
{
uint8_t digest[mhd_MD5_DIGEST_SIZE];
@@ -258,15 +244,13 @@ test1_str (void)
(const uint8_t *)data_units1[i].str_l.str);
mhd_MD5_finish_reset (&ctx,
digest);
-#if defined(MHD_MD5_EXTR)
if (mhd_MD5_has_err (&ctx))
{
fprintf (stderr,
"External hashing error: %d.\n",
- ctx.ext_error);
+ mhd_MD5_get_err (&ctx));
exit (99);
}
-#endif
num_failed += check_result (MHD_FUNC_,
i,
digest,
@@ -430,7 +414,7 @@ test1_bin (void)
unsigned int num_failed = 0;
struct mhd_Md5Ctx ctx;
- mhd_MD5_init_one_time (&ctx);
+ mhd_MD5_init (&ctx);
for (i = 0; i < units2_num; i++)
{
uint8_t digest[mhd_MD5_DIGEST_SIZE];
@@ -440,15 +424,13 @@ test1_bin (void)
data_units2[i].bin_l.bin);
mhd_MD5_finish_reset (&ctx,
digest);
-#if defined(MHD_MD5_EXTR)
if (mhd_MD5_has_err (&ctx))
{
fprintf (stderr,
"External hashing error: %d.\n",
- ctx.ext_error);
+ mhd_MD5_get_err (&ctx));
exit (99);
}
-#endif
num_failed += check_result (MHD_FUNC_,
i,
digest,
@@ -467,7 +449,7 @@ test2_str (void)
unsigned int num_failed = 0;
struct mhd_Md5Ctx ctx;
- mhd_MD5_init_one_time (&ctx);
+ mhd_MD5_init (&ctx);
for (i = 0; i < units1_num; i++)
{
uint8_t digest[mhd_MD5_DIGEST_SIZE];
@@ -483,15 +465,13 @@ test2_str (void)
(const uint8_t *)data_units1[i].str_l.str + part_s);
mhd_MD5_finish_reset (&ctx,
digest);
-#if defined(MHD_MD5_EXTR)
if (mhd_MD5_has_err (&ctx))
{
fprintf (stderr,
"External hashing error: %d.\n",
- ctx.ext_error);
+ mhd_MD5_get_err (&ctx));
exit (99);
}
-#endif
num_failed += check_result (MHD_FUNC_,
i,
digest,
@@ -509,7 +489,7 @@ test2_bin (void)
unsigned int num_failed = 0;
struct mhd_Md5Ctx ctx;
- mhd_MD5_init_one_time (&ctx);
+ mhd_MD5_init (&ctx);
for (i = 0; i < units2_num; i++)
{
@@ -524,15 +504,13 @@ test2_bin (void)
data_units2[i].bin_l.bin + part_s);
mhd_MD5_finish_reset (&ctx,
digest);
-#if defined(MHD_MD5_EXTR)
if (mhd_MD5_has_err (&ctx))
{
fprintf (stderr,
"External hashing error: %d.\n",
- ctx.ext_error);
+ mhd_MD5_get_err (&ctx));
exit (99);
}
-#endif
num_failed += check_result (MHD_FUNC_,
i,
digest,
@@ -563,7 +541,7 @@ test_unaligned (void)
|| (NULL == digest_buf))
exit (99);
- mhd_MD5_init_one_time (&ctx);
+ mhd_MD5_init (&ctx);
for (offset = MAX_OFFSET; offset >= 1; --offset)
{
@@ -583,15 +561,13 @@ test_unaligned (void)
unaligned_buf);
mhd_MD5_finish_reset (&ctx,
unaligned_digest);
-#if defined(MHD_MD5_EXTR)
if (mhd_MD5_has_err (&ctx))
{
fprintf (stderr,
"External hashing error: %d.\n",
- ctx.ext_error);
+ mhd_MD5_get_err (&ctx));
exit (99);
}
-#endif
num_failed += check_result (MHD_FUNC_,
MAX_OFFSET - offset,
unaligned_digest,
@@ -687,13 +663,13 @@ main (int argc,
"93b885adfe0da089cdf634904fd59f71" },
{ "Two bytes 0x00 0x00",
"0000",
- "c4103f122d27677c9db144cae1394a66" },
- { NULL, NULL, NULL }
+ "c4103f122d27677c9db144cae1394a66" }
};
struct mhd_Md5Ctx ctx;
uint8_t digest[mhd_MD5_DIGEST_SIZE];
uint8_t data[1024];
size_t data_len;
+ const char *test_name;
unsigned int passed = 0;
unsigned int total = 0;
unsigned int num_failed;
@@ -701,11 +677,11 @@ main (int argc,
if (mhdt_has_param (argc, argv, "-v")
|| mhdt_has_param (argc, argv, "--verbose"))
verbose = 1;
- while (NULL != tests[total].name)
+ for (total = 0; total < sizeof(tests) / sizeof(tests[0]); ++total)
{
const struct Test *t = &tests[total];
- mhd_MD5_init_one_time (&ctx);
+ mhd_MD5_init (&ctx);
if (!mhd_MD5_has_err (&ctx))
{
data_len = hex2bin (t->input,
@@ -727,24 +703,26 @@ main (int argc,
}
else
{
- printf ("FAIL: %s - error in finish\n",
+ printf ("FAIL: %s - digest function failed due to backend error\n",
t->name);
+ exit (99);
}
}
else
{
printf ("FAIL: %s - error in init\n",
t->name);
+ exit (99);
}
mhd_MD5_deinit (&ctx);
- total++;
}
/*
* Test update functionality
*/
total++;
- mhd_MD5_init_one_time (&ctx);
+ test_name = "Multi-update: a + b + c";
+ mhd_MD5_init (&ctx);
if (!mhd_MD5_has_err (&ctx))
{
data[0] = 'a';
@@ -766,9 +744,21 @@ main (int argc,
if (check_digest (digest,
mhd_MD5_DIGEST_SIZE,
"900150983cd24fb0d6963f7d28e17f72",
- "Multi-update: a + b + c"))
+ test_name))
passed++;
}
+ else
+ {
+ printf ("FAIL: %s - backend reported error\n",
+ test_name);
+ exit (99);
+ }
+ }
+ else
+ {
+ printf ("FAIL: %s - backend reported initialisation error\n",
+ test_name);
+ exit (99);
}
mhd_MD5_deinit (&ctx);
@@ -776,7 +766,8 @@ main (int argc,
* Tests finish_reset and reuse of context
*/
total++;
- mhd_MD5_init_one_time (&ctx);
+ test_name = "Reset and reuse context";
+ mhd_MD5_init (&ctx);
if (!mhd_MD5_has_err (&ctx))
{
/* First hash */
@@ -803,9 +794,21 @@ main (int argc,
if (check_digest (digest,
mhd_MD5_DIGEST_SIZE,
"900150983cd24fb0d6963f7d28e17f72",
- "Reset and reuse context"))
+ test_name))
passed++;
}
+ else
+ {
+ printf ("FAIL: %s - backend reported error\n",
+ test_name);
+ exit (99);
+ }
+ }
+ else
+ {
+ printf ("FAIL: %s - backend reported initialisation error\n",
+ test_name);
+ exit (99);
}
mhd_MD5_deinit (&ctx);