Coverage Report

Created: 2025-10-13 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mhd2/src/mhd2/md5_int.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
2
/*
3
  This file is part of GNU libmicrohttpd.
4
  Copyright (C) 2022-2024 Evgeny Grin (Karlson2k)
5
6
  GNU libmicrohttpd is free software; you can redistribute it and/or
7
  modify it under the terms of the GNU Lesser General Public
8
  License as published by the Free Software Foundation; either
9
  version 2.1 of the License, or (at your option) any later version.
10
11
  GNU libmicrohttpd is distributed in the hope that it will be useful,
12
  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
  Lesser General Public License for more details.
15
16
  Alternatively, you can redistribute GNU libmicrohttpd and/or
17
  modify it under the terms of the GNU General Public License as
18
  published by the Free Software Foundation; either version 2 of
19
  the License, or (at your option) any later version, together
20
  with the eCos exception, as follows:
21
22
    As a special exception, if other files instantiate templates or
23
    use macros or inline functions from this file, or you compile this
24
    file and link it with other works to produce a work based on this
25
    file, this file does not by itself cause the resulting work to be
26
    covered by the GNU General Public License. However the source code
27
    for this file must still be made available in accordance with
28
    section (3) of the GNU General Public License v2.
29
30
    This exception does not invalidate any other reasons why a work
31
    based on this file might be covered by the GNU General Public
32
    License.
33
34
  You should have received copies of the GNU Lesser General Public
35
  License and the GNU General Public License along with this library;
36
  if not, see <https://www.gnu.org/licenses/>.
37
*/
38
39
/**
40
 * @file src/mhd2/md5_int.c
41
 * @brief  Calculation of MD5 digest as defined in RFC 1321
42
 * @author Karlson2k (Evgeny Grin)
43
 */
44
45
#include "mhd_sys_options.h"
46
47
#include "sys_bool_type.h"
48
49
#include <string.h>
50
#include "mhd_bithelpers.h"
51
#include "mhd_assert.h"
52
53
#include "md5_int.h"
54
55
MHD_INTERNAL void MHD_FN_PAR_NONNULL_ALL_
56
mhd_MD5_init (struct mhd_Md5CtxInt *ctx)
57
0
{
58
  /* Initial hash values, see RFC 1321, Clause 3.3 (step 3). */
59
  /* Note: values specified in RFC by bytes and should be loaded in
60
           little-endian mode, therefore hash values here are initialised with
61
           original bytes used in little-endian order. */
62
0
  ctx->H[0] = UINT32_C (0x67452301);
63
0
  ctx->H[1] = UINT32_C (0xefcdab89);
64
0
  ctx->H[2] = UINT32_C (0x98badcfe);
65
0
  ctx->H[3] = UINT32_C (0x10325476);
66
67
  /* Initialise the number of bytes. */
68
0
  ctx->count = 0;
69
0
}
70
71
72
mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
73
74
/**
75
 * Base of MD5 transformation.
76
 * Gets full 64 bytes block of data and updates hash values;
77
 * @param H     hash values
78
 * @param M     the data buffer with #mhd_MD5_BLOCK_SIZE bytes block
79
 */
80
static MHD_FN_PAR_NONNULL_ALL_ void
81
md5_transform (uint32_t H[mhd_MD5_HASH_SIZE_WORDS],
82
               const void *restrict M)
83
0
{
84
  /* Working variables,
85
     See RFC 1321, Clause 3.4 (step 4). */
86
0
  uint32_t A = H[0];
87
0
  uint32_t B = H[1];
88
0
  uint32_t C = H[2];
89
0
  uint32_t D = H[3];
90
91
  /* The data buffer. See RFC 1321, Clause 3.4 (step 4). */
92
0
  uint32_t X[16];
93
94
0
#ifndef mhd_GET_32BIT_LE_UNALIGNED
95
0
  if (0 != (((uintptr_t) M) % mhd_UINT32_ALIGN))
96
0
  { /* The input data is unaligned. */
97
    /* Copy the unaligned input data to the aligned buffer. */
98
0
    memcpy (X, M, sizeof(X));
99
    /* The X[] buffer itself will be used as the source of the data,
100
     * but the data will be reloaded in correct bytes order on
101
     * the next steps. */
102
0
    M = (const void *) X;
103
0
  }
104
0
#endif /* mhd_GET_32BIT_LE_UNALIGNED */
105
106
  /* Four auxiliary functions, see RFC 1321, Clause 3.4 (step 4). */
107
  /* Some optimisations used. */
108
/* #define F_FUNC(x,y,z) (((x)&(y)) | ((~(x))&(z))) */ /* Original version */
109
0
#define F_FUNC(x,y,z) ((((y) ^ (z)) & (x)) ^ (z))
110
/* #define G_FUNC_1(x,y,z) (((x)&(z)) | ((y)&(~(z)))) */ /* Original version */
111
/* #define G_FUNC_2(x,y,z) UINT32_C(0) */ /* Original version */
112
0
#ifndef MHD_FAVOR_SMALL_CODE
113
0
#  define G_FUNC_1(x,y,z) ((~(z)) & (y))
114
0
#  define G_FUNC_2(x,y,z) ((z) & (x))
115
#else  /* MHD_FAVOR_SMALL_CODE */
116
#  define G_FUNC_1(x,y,z) ((((x) ^ (y)) & (z)) ^ (y))
117
#  define G_FUNC_2(x,y,z) UINT32_C (0)
118
#endif /* MHD_FAVOR_SMALL_CODE */
119
0
#define H_FUNC(x,y,z) ((x) ^ (y) ^ (z)) /* Original version */
120
/* #define I_FUNC(x,y,z) ((y) ^ ((x) | (~(z)))) */ /* Original version */
121
0
#define I_FUNC(x,y,z) (((~(z)) | (x)) ^ (y))
122
123
  /* One step of round 1 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
124
     The original function was modified to use X[k] and T[i] as
125
     direct inputs. */
126
0
#define MD5STEP_R1(va,vb,vc,vd,vX,vs,vT) do {          \
127
0
          (va) += (vX) + (vT);                               \
128
0
          (va) += F_FUNC ((vb),(vc),(vd));                    \
129
0
          (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
130
131
  /* Get value of X(k) from input data buffer.
132
     See RFC 1321 Clause 3.4 (step 4). */
133
0
#define GET_X_FROM_DATA(buf,t) \
134
0
        mhd_GET_32BIT_LE (((const uint32_t*) (buf)) + (t))
135
136
  /* One step of round 2 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
137
     The original function was modified to use X[k] and T[i] as
138
     direct inputs. */
139
0
#define MD5STEP_R2(va,vb,vc,vd,vX,vs,vT) do {         \
140
0
          (va) += (vX) + (vT);                              \
141
0
          (va) += G_FUNC_1 ((vb),(vc),(vd));                 \
142
0
          (va) += G_FUNC_2 ((vb),(vc),(vd));                 \
143
0
          (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
144
145
  /* One step of round 3 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
146
     The original function was modified to use X[k] and T[i] as
147
     direct inputs. */
148
0
#define MD5STEP_R3(va,vb,vc,vd,vX,vs,vT) do {         \
149
0
          (va) += (vX) + (vT);                              \
150
0
          (va) += H_FUNC ((vb),(vc),(vd));                   \
151
0
          (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
152
153
  /* One step of round 4 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
154
     The original function was modified to use X[k] and T[i] as
155
     direct inputs. */
156
0
#define MD5STEP_R4(va,vb,vc,vd,vX,vs,vT) do {         \
157
0
          (va) += (vX) + (vT);                              \
158
0
          (va) += I_FUNC ((vb),(vc),(vd));                   \
159
0
          (va) = mhd_ROTL32 ((va),(vs)) + (vb); } while (0)
160
161
0
#if ! defined(MHD_FAVOR_SMALL_CODE)
162
163
  /* Round 1. */
164
165
0
#if mhd_BYTE_ORDER == mhd_LITTLE_ENDIAN
166
0
  if ((const void *) X == M)
167
0
  {
168
    /* The input data is already in the data buffer X[] in correct bytes
169
       order. */
170
0
    MD5STEP_R1 (A, B, C, D, X[0],  7,  UINT32_C (0xd76aa478));
171
0
    MD5STEP_R1 (D, A, B, C, X[1],  12, UINT32_C (0xe8c7b756));
172
0
    MD5STEP_R1 (C, D, A, B, X[2],  17, UINT32_C (0x242070db));
173
0
    MD5STEP_R1 (B, C, D, A, X[3],  22, UINT32_C (0xc1bdceee));
174
175
0
    MD5STEP_R1 (A, B, C, D, X[4],  7,  UINT32_C (0xf57c0faf));
176
0
    MD5STEP_R1 (D, A, B, C, X[5],  12, UINT32_C (0x4787c62a));
177
0
    MD5STEP_R1 (C, D, A, B, X[6],  17, UINT32_C (0xa8304613));
178
0
    MD5STEP_R1 (B, C, D, A, X[7],  22, UINT32_C (0xfd469501));
179
180
0
    MD5STEP_R1 (A, B, C, D, X[8],  7,  UINT32_C (0x698098d8));
181
0
    MD5STEP_R1 (D, A, B, C, X[9],  12, UINT32_C (0x8b44f7af));
182
0
    MD5STEP_R1 (C, D, A, B, X[10], 17, UINT32_C (0xffff5bb1));
183
0
    MD5STEP_R1 (B, C, D, A, X[11], 22, UINT32_C (0x895cd7be));
184
185
0
    MD5STEP_R1 (A, B, C, D, X[12], 7,  UINT32_C (0x6b901122));
186
0
    MD5STEP_R1 (D, A, B, C, X[13], 12, UINT32_C (0xfd987193));
187
0
    MD5STEP_R1 (C, D, A, B, X[14], 17, UINT32_C (0xa679438e));
188
0
    MD5STEP_R1 (B, C, D, A, X[15], 22, UINT32_C (0x49b40821));
189
0
  }
190
0
  else /* Combined with the next 'if' */
191
0
#endif /* mhd_BYTE_ORDER == mhd_LITTLE_ENDIAN */
192
0
  if (1)
193
0
  {
194
    /* The input data is loaded in correct (little-endian) format before
195
       calculations on each step. */
196
0
    MD5STEP_R1 (A, B, C, D, X[0]  = GET_X_FROM_DATA (M, 0),  7, \
197
0
                UINT32_C (0xd76aa478));
198
0
    MD5STEP_R1 (D, A, B, C, X[1]  = GET_X_FROM_DATA (M, 1),  12, \
199
0
                UINT32_C (0xe8c7b756));
200
0
    MD5STEP_R1 (C, D, A, B, X[2]  = GET_X_FROM_DATA (M, 2),  17, \
201
0
                UINT32_C (0x242070db));
202
0
    MD5STEP_R1 (B, C, D, A, X[3]  = GET_X_FROM_DATA (M, 3),  22, \
203
0
                UINT32_C (0xc1bdceee));
204
205
0
    MD5STEP_R1 (A, B, C, D, X[4]  = GET_X_FROM_DATA (M, 4),  7, \
206
0
                UINT32_C (0xf57c0faf));
207
0
    MD5STEP_R1 (D, A, B, C, X[5]  = GET_X_FROM_DATA (M, 5),  12, \
208
0
                UINT32_C (0x4787c62a));
209
0
    MD5STEP_R1 (C, D, A, B, X[6]  = GET_X_FROM_DATA (M, 6),  17, \
210
0
                UINT32_C (0xa8304613));
211
0
    MD5STEP_R1 (B, C, D, A, X[7]  = GET_X_FROM_DATA (M, 7),  22, \
212
0
                UINT32_C (0xfd469501));
213
214
0
    MD5STEP_R1 (A, B, C, D, X[8]  = GET_X_FROM_DATA (M, 8),  7, \
215
0
                UINT32_C (0x698098d8));
216
0
    MD5STEP_R1 (D, A, B, C, X[9]  = GET_X_FROM_DATA (M, 9),  12, \
217
0
                UINT32_C (0x8b44f7af));
218
0
    MD5STEP_R1 (C, D, A, B, X[10] = GET_X_FROM_DATA (M, 10), 17, \
219
0
                UINT32_C (0xffff5bb1));
220
0
    MD5STEP_R1 (B, C, D, A, X[11] = GET_X_FROM_DATA (M, 11), 22, \
221
0
                UINT32_C (0x895cd7be));
222
223
0
    MD5STEP_R1 (A, B, C, D, X[12] = GET_X_FROM_DATA (M, 12), 7, \
224
0
                UINT32_C (0x6b901122));
225
0
    MD5STEP_R1 (D, A, B, C, X[13] = GET_X_FROM_DATA (M, 13), 12, \
226
0
                UINT32_C (0xfd987193));
227
0
    MD5STEP_R1 (C, D, A, B, X[14] = GET_X_FROM_DATA (M, 14), 17, \
228
0
                UINT32_C (0xa679438e));
229
0
    MD5STEP_R1 (B, C, D, A, X[15] = GET_X_FROM_DATA (M, 15), 22, \
230
0
                UINT32_C (0x49b40821));
231
0
  }
232
233
  /* Round 2. */
234
235
0
  MD5STEP_R2 (A, B, C, D, X[1], 5, UINT32_C (0xf61e2562));
236
0
  MD5STEP_R2 (D, A, B, C, X[6], 9, UINT32_C (0xc040b340));
237
0
  MD5STEP_R2 (C, D, A, B, X[11], 14, UINT32_C (0x265e5a51));
238
0
  MD5STEP_R2 (B, C, D, A, X[0], 20, UINT32_C (0xe9b6c7aa));
239
240
0
  MD5STEP_R2 (A, B, C, D, X[5], 5, UINT32_C (0xd62f105d));
241
0
  MD5STEP_R2 (D, A, B, C, X[10], 9, UINT32_C (0x02441453));
242
0
  MD5STEP_R2 (C, D, A, B, X[15], 14, UINT32_C (0xd8a1e681));
243
0
  MD5STEP_R2 (B, C, D, A, X[4], 20, UINT32_C (0xe7d3fbc8));
244
245
0
  MD5STEP_R2 (A, B, C, D, X[9], 5, UINT32_C (0x21e1cde6));
246
0
  MD5STEP_R2 (D, A, B, C, X[14], 9, UINT32_C (0xc33707d6));
247
0
  MD5STEP_R2 (C, D, A, B, X[3], 14, UINT32_C (0xf4d50d87));
248
0
  MD5STEP_R2 (B, C, D, A, X[8], 20, UINT32_C (0x455a14ed));
249
250
0
  MD5STEP_R2 (A, B, C, D, X[13], 5, UINT32_C (0xa9e3e905));
251
0
  MD5STEP_R2 (D, A, B, C, X[2], 9, UINT32_C (0xfcefa3f8));
252
0
  MD5STEP_R2 (C, D, A, B, X[7], 14, UINT32_C (0x676f02d9));
253
0
  MD5STEP_R2 (B, C, D, A, X[12], 20, UINT32_C (0x8d2a4c8a));
254
255
  /* Round 3. */
256
257
0
  MD5STEP_R3 (A, B, C, D, X[5], 4, UINT32_C (0xfffa3942));
258
0
  MD5STEP_R3 (D, A, B, C, X[8], 11, UINT32_C (0x8771f681));
259
0
  MD5STEP_R3 (C, D, A, B, X[11], 16, UINT32_C (0x6d9d6122));
260
0
  MD5STEP_R3 (B, C, D, A, X[14], 23, UINT32_C (0xfde5380c));
261
262
0
  MD5STEP_R3 (A, B, C, D, X[1], 4, UINT32_C (0xa4beea44));
263
0
  MD5STEP_R3 (D, A, B, C, X[4], 11, UINT32_C (0x4bdecfa9));
264
0
  MD5STEP_R3 (C, D, A, B, X[7], 16, UINT32_C (0xf6bb4b60));
265
0
  MD5STEP_R3 (B, C, D, A, X[10], 23, UINT32_C (0xbebfbc70));
266
267
0
  MD5STEP_R3 (A, B, C, D, X[13], 4, UINT32_C (0x289b7ec6));
268
0
  MD5STEP_R3 (D, A, B, C, X[0], 11, UINT32_C (0xeaa127fa));
269
0
  MD5STEP_R3 (C, D, A, B, X[3], 16, UINT32_C (0xd4ef3085));
270
0
  MD5STEP_R3 (B, C, D, A, X[6], 23, UINT32_C (0x04881d05));
271
272
0
  MD5STEP_R3 (A, B, C, D, X[9], 4, UINT32_C (0xd9d4d039));
273
0
  MD5STEP_R3 (D, A, B, C, X[12], 11, UINT32_C (0xe6db99e5));
274
0
  MD5STEP_R3 (C, D, A, B, X[15], 16, UINT32_C (0x1fa27cf8));
275
0
  MD5STEP_R3 (B, C, D, A, X[2], 23, UINT32_C (0xc4ac5665));
276
277
  /* Round 4. */
278
279
0
  MD5STEP_R4 (A, B, C, D, X[0], 6, UINT32_C (0xf4292244));
280
0
  MD5STEP_R4 (D, A, B, C, X[7], 10, UINT32_C (0x432aff97));
281
0
  MD5STEP_R4 (C, D, A, B, X[14], 15, UINT32_C (0xab9423a7));
282
0
  MD5STEP_R4 (B, C, D, A, X[5], 21, UINT32_C (0xfc93a039));
283
284
0
  MD5STEP_R4 (A, B, C, D, X[12], 6, UINT32_C (0x655b59c3));
285
0
  MD5STEP_R4 (D, A, B, C, X[3], 10, UINT32_C (0x8f0ccc92));
286
0
  MD5STEP_R4 (C, D, A, B, X[10], 15, UINT32_C (0xffeff47d));
287
0
  MD5STEP_R4 (B, C, D, A, X[1], 21, UINT32_C (0x85845dd1));
288
289
0
  MD5STEP_R4 (A, B, C, D, X[8], 6, UINT32_C (0x6fa87e4f));
290
0
  MD5STEP_R4 (D, A, B, C, X[15], 10, UINT32_C (0xfe2ce6e0));
291
0
  MD5STEP_R4 (C, D, A, B, X[6], 15, UINT32_C (0xa3014314));
292
0
  MD5STEP_R4 (B, C, D, A, X[13], 21, UINT32_C (0x4e0811a1));
293
294
0
  MD5STEP_R4 (A, B, C, D, X[4], 6, UINT32_C (0xf7537e82));
295
0
  MD5STEP_R4 (D, A, B, C, X[11], 10, UINT32_C (0xbd3af235));
296
0
  MD5STEP_R4 (C, D, A, B, X[2], 15, UINT32_C (0x2ad7d2bb));
297
0
  MD5STEP_R4 (B, C, D, A, X[9], 21, UINT32_C (0xeb86d391));
298
#else  /* MHD_FAVOR_SMALL_CODE */
299
  if (1)
300
  {
301
    static const uint32_t T[64] =
302
    { UINT32_C (0xd76aa478), UINT32_C (0xe8c7b756), UINT32_C (0x242070db),
303
      UINT32_C (0xc1bdceee), UINT32_C (0xf57c0faf), UINT32_C (0x4787c62a),
304
      UINT32_C (0xa8304613), UINT32_C (0xfd469501), UINT32_C (0x698098d8),
305
      UINT32_C (0x8b44f7af), UINT32_C (0xffff5bb1), UINT32_C (0x895cd7be),
306
      UINT32_C (0x6b901122), UINT32_C (0xfd987193), UINT32_C (0xa679438e),
307
      UINT32_C (0x49b40821), UINT32_C (0xf61e2562), UINT32_C (0xc040b340),
308
      UINT32_C (0x265e5a51), UINT32_C (0xe9b6c7aa), UINT32_C (0xd62f105d),
309
      UINT32_C (0x02441453), UINT32_C (0xd8a1e681), UINT32_C (0xe7d3fbc8),
310
      UINT32_C (0x21e1cde6), UINT32_C (0xc33707d6), UINT32_C (0xf4d50d87),
311
      UINT32_C (0x455a14ed), UINT32_C (0xa9e3e905), UINT32_C (0xfcefa3f8),
312
      UINT32_C (0x676f02d9), UINT32_C (0x8d2a4c8a), UINT32_C (0xfffa3942),
313
      UINT32_C (0x8771f681), UINT32_C (0x6d9d6122), UINT32_C (0xfde5380c),
314
      UINT32_C (0xa4beea44), UINT32_C (0x4bdecfa9), UINT32_C (0xf6bb4b60),
315
      UINT32_C (0xbebfbc70), UINT32_C (0x289b7ec6), UINT32_C (0xeaa127fa),
316
      UINT32_C (0xd4ef3085), UINT32_C (0x04881d05), UINT32_C (0xd9d4d039),
317
      UINT32_C (0xe6db99e5), UINT32_C (0x1fa27cf8), UINT32_C (0xc4ac5665),
318
      UINT32_C (0xf4292244), UINT32_C (0x432aff97), UINT32_C (0xab9423a7),
319
      UINT32_C (0xfc93a039), UINT32_C (0x655b59c3), UINT32_C (0x8f0ccc92),
320
      UINT32_C (0xffeff47d), UINT32_C (0x85845dd1), UINT32_C (0x6fa87e4f),
321
      UINT32_C (0xfe2ce6e0), UINT32_C (0xa3014314), UINT32_C (0x4e0811a1),
322
      UINT32_C (0xf7537e82), UINT32_C (0xbd3af235), UINT32_C (0x2ad7d2bb),
323
      UINT32_C (0xeb86d391) };
324
    unsigned int i; /**< Zero-based index */
325
326
    /* Round 1. */
327
328
    i = 0;
329
    do
330
    {
331
      /* The input data is loaded in correct (little-endian) format before
332
         calculations on each step. */
333
      MD5STEP_R1 (A, B, C, D, X[i]  = GET_X_FROM_DATA (M, i),  7,  T[i]);
334
      ++i;
335
      MD5STEP_R1 (D, A, B, C, X[i]  = GET_X_FROM_DATA (M, i),  12, T[i]);
336
      ++i;
337
      MD5STEP_R1 (C, D, A, B, X[i]  = GET_X_FROM_DATA (M, i),  17, T[i]);
338
      ++i;
339
      MD5STEP_R1 (B, C, D, A, X[i]  = GET_X_FROM_DATA (M, i),  22, T[i]);
340
      ++i;
341
    } while (i < 16);
342
343
    /* Round 2. */
344
345
    do
346
    {
347
      const unsigned int idx_add = i;
348
      MD5STEP_R2 (A, B, C, D, X[(1U  + idx_add) & 15U], 5,  T[i]);
349
      ++i;
350
      MD5STEP_R2 (D, A, B, C, X[(6U  + idx_add) & 15U], 9,  T[i]);
351
      ++i;
352
      MD5STEP_R2 (C, D, A, B, X[(11U + idx_add) & 15U], 14, T[i]);
353
      ++i;
354
      MD5STEP_R2 (B, C, D, A, X[(0U  + idx_add) & 15U], 20, T[i]);
355
      ++i;
356
    } while (i < 32);
357
358
    /* Round 3. */
359
360
    do
361
    {
362
      const unsigned int idx_add = i;
363
      MD5STEP_R3 (A, B, C, D, X[(5U  + 64U - idx_add) & 15U], 4,  T[i]);
364
      ++i;
365
      MD5STEP_R3 (D, A, B, C, X[(8U  + 64U - idx_add) & 15U], 11, T[i]);
366
      ++i;
367
      MD5STEP_R3 (C, D, A, B, X[(11U + 64U - idx_add) & 15U], 16, T[i]);
368
      ++i;
369
      MD5STEP_R3 (B, C, D, A, X[(14U + 64U - idx_add) & 15U], 23, T[i]);
370
      ++i;
371
    } while (i < 48);
372
373
    /* Round 4. */
374
375
    do
376
    {
377
      const unsigned int idx_add = i;
378
      MD5STEP_R4 (A, B, C, D, X[(0U  + 64U - idx_add) & 15U], 6,  T[i]);
379
      ++i;
380
      MD5STEP_R4 (D, A, B, C, X[(7U  + 64U - idx_add) & 15U], 10, T[i]);
381
      ++i;
382
      MD5STEP_R4 (C, D, A, B, X[(14U + 64U - idx_add) & 15U], 15, T[i]);
383
      ++i;
384
      MD5STEP_R4 (B, C, D, A, X[(5U  + 64U - idx_add) & 15U], 21, T[i]);
385
      ++i;
386
    } while (i < 64);
387
  }
388
#endif /* MHD_FAVOR_SMALL_CODE */
389
390
  /* Finally increment and store working variables.
391
     See RFC 1321, end of Clause 3.4 (step 4). */
392
393
0
  H[0] += A;
394
0
  H[1] += B;
395
0
  H[2] += C;
396
0
  H[3] += D;
397
0
}
398
399
400
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
401
MHD_FN_PAR_IN_SIZE_ (3, 2) void
402
mhd_MD5_update (struct mhd_Md5CtxInt *restrict ctx,
403
                size_t size,
404
                const uint8_t *restrict data)
405
0
{
406
0
  unsigned int bytes_have; /**< Number of bytes in the context buffer */
407
408
0
  mhd_assert (0 != size);
409
410
  /* Note: (count & (mhd_MD5_BLOCK_SIZE-1))
411
           equals (count % mhd_MD5_BLOCK_SIZE) for this block size. */
412
0
  bytes_have = (unsigned int) (ctx->count & (mhd_MD5_BLOCK_SIZE - 1));
413
0
  ctx->count += size;
414
415
0
  if (0 != bytes_have)
416
0
  {
417
0
    unsigned int bytes_left = mhd_MD5_BLOCK_SIZE - bytes_have;
418
0
    if (size >= bytes_left)
419
0
    {     /* Combine new data with data in the buffer and
420
             process the full block. */
421
0
      memcpy (((uint8_t *) ctx->buffer) + bytes_have,
422
0
              data,
423
0
              bytes_left);
424
0
      data += bytes_left;
425
0
      size -= bytes_left;
426
0
      md5_transform (ctx->H, ctx->buffer);
427
0
      bytes_have = 0;
428
0
    }
429
0
  }
430
431
0
  while (mhd_MD5_BLOCK_SIZE <= size)
432
0
  {   /* Process any full blocks of new data directly,
433
         without copying to the buffer. */
434
0
    md5_transform (ctx->H, data);
435
0
    data += mhd_MD5_BLOCK_SIZE;
436
0
    size -= mhd_MD5_BLOCK_SIZE;
437
0
  }
438
439
0
  if (0 != size)
440
0
  {   /* Copy incomplete block of new data (if any)
441
         to the buffer. */
442
0
    memcpy (((uint8_t *) ctx->buffer) + bytes_have, data, size);
443
0
  }
444
0
}
445
446
447
/**
448
 * Size of "length" insertion in bits.
449
 * See RFC 1321, end of Clause 3.2 (step 2).
450
 */
451
0
#define MD5_SIZE_OF_LEN_ADD_BITS 64
452
453
/**
454
 * Size of "length" insertion in bytes.
455
 */
456
0
#define MD5_SIZE_OF_LEN_ADD (MD5_SIZE_OF_LEN_ADD_BITS / 8)
457
458
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
459
MHD_FN_PAR_OUT_ (2) void
460
mhd_MD5_finish (struct mhd_Md5CtxInt *restrict ctx,
461
                uint8_t digest[mhd_MD5_DIGEST_SIZE])
462
0
{
463
0
  uint64_t num_bits;   /**< Number of processed bits */
464
0
  unsigned int bytes_have; /**< Number of bytes in the context buffer */
465
466
  /* Memorise the number of processed bits.
467
     The padding and other data added here during the postprocessing must
468
     not change the amount of hashed data. */
469
0
  num_bits = ctx->count << 3;
470
471
  /* Note: (count & (mhd_MD5_BLOCK_SIZE-1))
472
           equals (count % mhd_MD5_BLOCK_SIZE) for this block size. */
473
0
  bytes_have = (unsigned int) (ctx->count & (mhd_MD5_BLOCK_SIZE - 1));
474
475
  /* Input data must be padded with a single bit "1", then with zeros and
476
     the finally the length of data in bits must be added as the final bytes
477
     of the last block.
478
     See RFC 1321, Clauses 3.1 and 3.2 (steps 1 and 2). */
479
  /* Data is always processed in form of bytes (not by individual bits),
480
     therefore position of the first padding bit in byte is always
481
     predefined (0x80). */
482
  /* Buffer always have space for one byte at least (as full buffers are
483
     processed immediately). */
484
0
  ((uint8_t *) ctx->buffer)[bytes_have++] = 0x80;
485
486
0
  if (mhd_MD5_BLOCK_SIZE - bytes_have < MD5_SIZE_OF_LEN_ADD)
487
0
  {   /* No space in the current block to put the total length of message.
488
         Pad the current block with zeros and process it. */
489
0
    if (bytes_have < mhd_MD5_BLOCK_SIZE)
490
0
      memset (((uint8_t *) ctx->buffer) + bytes_have, 0,
491
0
              mhd_MD5_BLOCK_SIZE - bytes_have);
492
    /* Process the full block. */
493
0
    md5_transform (ctx->H, ctx->buffer);
494
    /* Start the new block. */
495
0
    bytes_have = 0;
496
0
  }
497
498
  /* Pad the rest of the buffer with zeros. */
499
0
  memset (((uint8_t *) ctx->buffer) + bytes_have, 0,
500
0
          mhd_MD5_BLOCK_SIZE - MD5_SIZE_OF_LEN_ADD - bytes_have);
501
  /* Put the number of bits in processed data as little-endian value.
502
     See RFC 1321, clauses 2 and 3.2 (step 2). */
503
0
  mhd_PUT_64BIT_LE_UNALIGN (ctx->buffer + mhd_MD5_BLOCK_SIZE_WORDS - 2,
504
0
                            num_bits);
505
  /* Process the full final block. */
506
0
  md5_transform (ctx->H, ctx->buffer);
507
508
  /* Put in LE mode the hash as the final digest.
509
     See RFC 1321, clauses 2 and 3.5 (step 5). */
510
0
  if (1)
511
0
  {
512
0
    bool use_tmp_buf_to_align_result;
513
514
#if defined(mhd_PUT_32BIT_LE_UNALIGNED)
515
    use_tmp_buf_to_align_result = false;
516
#elif defined (MHD_FAVOR_SMALL_CODE)
517
    use_tmp_buf_to_align_result = true; /* smaller code: eliminated branch below */
518
#else
519
0
    use_tmp_buf_to_align_result =
520
0
      (0 != ((uintptr_t) digest) % mhd_UINT32_ALIGN);
521
0
#endif
522
0
    if (use_tmp_buf_to_align_result)
523
0
    {
524
      /* If storing of the final result requires aligned address and
525
         the destination address is not aligned or compact code is used,
526
         store the final digest in aligned temporary buffer first, then
527
         copy it to the destination. */
528
0
      uint32_t alig_dgst[mhd_MD5_DIGEST_SIZE_WORDS];
529
0
      mhd_PUT_32BIT_LE (alig_dgst + 0, ctx->H[0]);
530
0
      mhd_PUT_32BIT_LE (alig_dgst + 1, ctx->H[1]);
531
0
      mhd_PUT_32BIT_LE (alig_dgst + 2, ctx->H[2]);
532
0
      mhd_PUT_32BIT_LE (alig_dgst + 3, ctx->H[3]);
533
      /* Copy result to the unaligned destination address. */
534
0
      memcpy (digest, alig_dgst, mhd_MD5_DIGEST_SIZE);
535
0
    }
536
0
    else
537
0
    {
538
      /* Use cast to (void*) here to mute compiler alignment warnings.
539
       * Compilers are not smart enough to see that alignment has been checked. */
540
0
      mhd_PUT_32BIT_LE ((void *) (digest + 0 * mhd_MD5_BYTES_IN_WORD), \
541
0
                        ctx->H[0]);
542
0
      mhd_PUT_32BIT_LE ((void *) (digest + 1 * mhd_MD5_BYTES_IN_WORD), \
543
0
                        ctx->H[1]);
544
0
      mhd_PUT_32BIT_LE ((void *) (digest + 2 * mhd_MD5_BYTES_IN_WORD), \
545
0
                        ctx->H[2]);
546
0
      mhd_PUT_32BIT_LE ((void *) (digest + 3 * mhd_MD5_BYTES_IN_WORD), \
547
0
                        ctx->H[3]);
548
0
    }
549
0
  }
550
551
  /* Erase potentially sensitive data. */
552
0
  memset (ctx, 0, sizeof(struct mhd_Md5CtxInt));
553
0
}
554
555
556
mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE