Coverage Report

Created: 2026-06-02 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/hash/hash_md.c
Line
Count
Source
1
/*
2
  +----------------------------------------------------------------------+
3
  | Copyright © The PHP Group and Contributors.                          |
4
  +----------------------------------------------------------------------+
5
  | This source file is subject to the Modified BSD License that is      |
6
  | bundled with this package in the file LICENSE, and is available      |
7
  | through the World Wide Web at <https://www.php.net/license/>.        |
8
  |                                                                      |
9
  | SPDX-License-Identifier: BSD-3-Clause                                |
10
  +----------------------------------------------------------------------+
11
  | Taken from: ext/standard/md5.c                                       |
12
  +----------------------------------------------------------------------+
13
*/
14
15
#include "php_hash.h"
16
#include "php_hash_md.h"
17
18
const php_hash_ops php_hash_md5_ops = {
19
  "md5",
20
  (php_hash_init_func_t) PHP_MD5InitArgs,
21
  (php_hash_update_func_t) PHP_MD5Update,
22
  (php_hash_final_func_t) PHP_MD5Final,
23
  php_hash_copy,
24
  php_hash_serialize,
25
  php_hash_unserialize,
26
  PHP_MD5_SPEC,
27
  16,
28
  64,
29
  sizeof(PHP_MD5_CTX),
30
  1
31
};
32
33
const php_hash_ops php_hash_md4_ops = {
34
  "md4",
35
  (php_hash_init_func_t) PHP_MD4InitArgs,
36
  (php_hash_update_func_t) PHP_MD4Update,
37
  (php_hash_final_func_t) PHP_MD4Final,
38
  php_hash_copy,
39
  php_hash_serialize,
40
  php_hash_unserialize,
41
  PHP_MD4_SPEC,
42
  16,
43
  64,
44
  sizeof(PHP_MD4_CTX),
45
  1
46
};
47
48
static hash_spec_result php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv);
49
50
const php_hash_ops php_hash_md2_ops = {
51
  "md2",
52
  (php_hash_init_func_t) PHP_MD2InitArgs,
53
  (php_hash_update_func_t) PHP_MD2Update,
54
  (php_hash_final_func_t) PHP_MD2Final,
55
  php_hash_copy,
56
  php_hash_serialize,
57
  php_md2_unserialize,
58
  PHP_MD2_SPEC,
59
  16,
60
  16,
61
  sizeof(PHP_MD2_CTX),
62
  1
63
};
64
65
/* MD common stuff */
66
67
static const unsigned char PADDING[64] =
68
{
69
  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
72
};
73
74
/* {{{ Encode
75
   Encodes input (uint32_t) into output (unsigned char). Assumes len is
76
   a multiple of 4.
77
 */
78
static void Encode(unsigned char *output, uint32_t *input, unsigned int len)
79
0
{
80
0
  unsigned int i, j;
81
82
0
  for (i = 0, j = 0; j < len; i++, j += 4) {
83
0
    output[j] = (unsigned char) (input[i] & 0xff);
84
0
    output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
85
0
    output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
86
0
    output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
87
0
  }
88
0
}
89
/* }}} */
90
91
/* {{{ Decode
92
   Decodes input (unsigned char) into output (uint32_t). Assumes len is
93
   a multiple of 4.
94
 */
95
static void Decode(uint32_t *output, const unsigned char *input, unsigned int len)
96
0
{
97
0
  unsigned int i, j;
98
99
0
  for (i = 0, j = 0; j < len; i++, j += 4)
100
0
    output[i] = ((uint32_t) input[j]) | (((uint32_t) input[j + 1]) << 8) |
101
0
      (((uint32_t) input[j + 2]) << 16) | (((uint32_t) input[j + 3]) << 24);
102
0
}
103
/* }}} */
104
105
/* MD4 */
106
107
#define MD4_F(x,y,z)      ((z) ^ ((x) & ((y) ^ (z))))
108
#define MD4_G(x,y,z)      (((x) & ((y) | (z))) | ((y) & (z)))
109
#define MD4_H(x,y,z)      ((x) ^ (y) ^ (z))
110
111
0
#define ROTL32(s,v)       (((v) << (s)) | ((v) >> (32 - (s))))
112
113
0
#define MD4_R1(a,b,c,d,k,s)   a = ROTL32(s, a + MD4_F(b,c,d) + x[k])
114
0
#define MD4_R2(a,b,c,d,k,s)   a = ROTL32(s, a + MD4_G(b,c,d) + x[k] + 0x5A827999)
115
0
#define MD4_R3(a,b,c,d,k,s)   a = ROTL32(s, a + MD4_H(b,c,d) + x[k] + 0x6ED9EBA1)
116
117
static void MD4Transform(uint32_t state[4], const unsigned char block[64])
118
0
{
119
0
  uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
120
121
0
  Decode(x, block, 64);
122
123
  /* Round 1 */
124
0
  MD4_R1(a,b,c,d, 0, 3);
125
0
  MD4_R1(d,a,b,c, 1, 7);
126
0
  MD4_R1(c,d,a,b, 2,11);
127
0
  MD4_R1(b,c,d,a, 3,19);
128
0
  MD4_R1(a,b,c,d, 4, 3);
129
0
  MD4_R1(d,a,b,c, 5, 7);
130
0
  MD4_R1(c,d,a,b, 6,11);
131
0
  MD4_R1(b,c,d,a, 7,19);
132
0
  MD4_R1(a,b,c,d, 8, 3);
133
0
  MD4_R1(d,a,b,c, 9, 7);
134
0
  MD4_R1(c,d,a,b,10,11);
135
0
  MD4_R1(b,c,d,a,11,19);
136
0
  MD4_R1(a,b,c,d,12, 3);
137
0
  MD4_R1(d,a,b,c,13, 7);
138
0
  MD4_R1(c,d,a,b,14,11);
139
0
  MD4_R1(b,c,d,a,15,19);
140
141
  /* Round 2 */
142
0
  MD4_R2(a,b,c,d, 0, 3);
143
0
  MD4_R2(d,a,b,c, 4, 5);
144
0
  MD4_R2(c,d,a,b, 8, 9);
145
0
  MD4_R2(b,c,d,a,12,13);
146
0
  MD4_R2(a,b,c,d, 1, 3);
147
0
  MD4_R2(d,a,b,c, 5, 5);
148
0
  MD4_R2(c,d,a,b, 9, 9);
149
0
  MD4_R2(b,c,d,a,13,13);
150
0
  MD4_R2(a,b,c,d, 2, 3);
151
0
  MD4_R2(d,a,b,c, 6, 5);
152
0
  MD4_R2(c,d,a,b,10, 9);
153
0
  MD4_R2(b,c,d,a,14,13);
154
0
  MD4_R2(a,b,c,d, 3, 3);
155
0
  MD4_R2(d,a,b,c, 7, 5);
156
0
  MD4_R2(c,d,a,b,11, 9);
157
0
  MD4_R2(b,c,d,a,15,13);
158
159
  /* Round 3 */
160
0
  MD4_R3(a,b,c,d, 0, 3);
161
0
  MD4_R3(d,a,b,c, 8, 9);
162
0
  MD4_R3(c,d,a,b, 4,11);
163
0
  MD4_R3(b,c,d,a,12,15);
164
0
  MD4_R3(a,b,c,d, 2, 3);
165
0
  MD4_R3(d,a,b,c,10, 9);
166
0
  MD4_R3(c,d,a,b, 6,11);
167
0
  MD4_R3(b,c,d,a,14,15);
168
0
  MD4_R3(a,b,c,d, 1, 3);
169
0
  MD4_R3(d,a,b,c, 9, 9);
170
0
  MD4_R3(c,d,a,b, 5,11);
171
0
  MD4_R3(b,c,d,a,13,15);
172
0
  MD4_R3(a,b,c,d, 3, 3);
173
0
  MD4_R3(d,a,b,c,11, 9);
174
0
  MD4_R3(c,d,a,b, 7,11);
175
0
  MD4_R3(b,c,d,a,15,15);
176
177
0
  state[0] += a;
178
0
  state[1] += b;
179
0
  state[2] += c;
180
0
  state[3] += d;
181
0
}
182
183
/* {{{ PHP_MD4InitArgs
184
 * MD4 initialization. Begins an MD4 operation, writing a new context.
185
 */
186
PHP_HASH_API void PHP_MD4InitArgs(PHP_MD4_CTX * context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
187
0
{
188
0
  context->count[0] = context->count[1] = 0;
189
  /* Load magic initialization constants.
190
   */
191
0
  context->state[0] = 0x67452301;
192
0
  context->state[1] = 0xefcdab89;
193
0
  context->state[2] = 0x98badcfe;
194
0
  context->state[3] = 0x10325476;
195
0
}
196
/* }}} */
197
198
/* {{{ PHP_MD4Update
199
   MD4 block update operation. Continues an MD4 message-digest
200
   operation, processing another message block, and updating the
201
   context.
202
 */
203
PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *input, size_t inputLen)
204
0
{
205
0
  unsigned int index, partLen;
206
0
  size_t i;
207
208
  /* Compute number of bytes mod 64 */
209
0
  index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
210
211
  /* Update number of bits */
212
0
  if ((context->count[0] += ((uint32_t) inputLen << 3))
213
0
    < ((uint32_t) inputLen << 3))
214
0
    context->count[1]++;
215
0
  context->count[1] += (uint32_t) (inputLen >> 29);
216
217
0
  partLen = 64 - index;
218
219
  /* Transform as many times as possible.
220
   */
221
0
  if (inputLen >= partLen) {
222
0
    memcpy((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen);
223
0
    MD4Transform(context->state, context->buffer);
224
225
0
    for (i = partLen; i + 63 < inputLen; i += 64) {
226
0
      MD4Transform(context->state, &input[i]);
227
0
    }
228
229
0
    index = 0;
230
0
  } else {
231
0
    i = 0;
232
0
  }
233
234
  /* Buffer remaining input */
235
0
  memcpy((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], inputLen - i);
236
0
}
237
/* }}} */
238
239
/* {{{ PHP_MD4Final
240
   MD4 finalization. Ends an MD4 message-digest operation, writing
241
   the message digest and zeroizing the context.
242
 */
243
PHP_HASH_API void PHP_MD4Final(unsigned char digest[16], PHP_MD4_CTX * context)
244
0
{
245
0
  unsigned char bits[8];
246
0
  unsigned int index, padLen;
247
248
  /* Save number of bits */
249
0
  Encode(bits, context->count, 8);
250
251
  /* Pad out to 56 mod 64.
252
   */
253
0
  index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
254
0
  padLen = (index < 56) ? (56 - index) : (120 - index);
255
0
  PHP_MD4Update(context, PADDING, padLen);
256
257
  /* Append length (before padding) */
258
0
  PHP_MD4Update(context, bits, 8);
259
260
  /* Store state in digest */
261
0
  Encode(digest, context->state, 16);
262
263
  /* Zeroize sensitive information.
264
   */
265
0
  ZEND_SECURE_ZERO((unsigned char*) context, sizeof(*context));
266
0
}
267
/* }}} */
268
269
/* MD2 */
270
271
static const unsigned char MD2_S[256] = {
272
   41,  46,  67, 201, 162, 216, 124,   1,  61,  54,  84, 161, 236, 240,   6,  19,
273
   98, 167,   5, 243, 192, 199, 115, 140, 152, 147,  43, 217, 188,  76, 130, 202,
274
   30, 155,  87,  60, 253, 212, 224,  22, 103,  66, 111,  24, 138,  23, 229,  18,
275
  190,  78, 196, 214, 218, 158, 222,  73, 160, 251, 245, 142, 187,  47, 238, 122,
276
  169, 104, 121, 145,  21, 178,   7,  63, 148, 194,  16, 137,  11,  34,  95,  33,
277
  128, 127,  93, 154,  90, 144,  50,  39,  53,  62, 204, 231, 191, 247, 151,   3,
278
  255,  25,  48, 179,  72, 165, 181, 209, 215,  94, 146,  42, 172,  86, 170, 198,
279
   79, 184,  56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116,   4, 241,
280
   69, 157, 112,  89, 100, 113, 135,  32, 134,  91, 207, 101, 230,  45, 168,   2,
281
   27,  96,  37, 173, 174, 176, 185, 246,  28,  70,  97, 105,  52,  64, 126,  15,
282
   85,  71, 163,  35, 221,  81, 175,  58, 195,  92, 249, 206, 186, 197, 234,  38,
283
   44,  83,  13, 110, 133,  40, 132,   9, 211, 223, 205, 244,  65, 129,  77,  82,
284
  106, 220,  55, 200, 108, 193, 171, 250,  36, 225, 123,   8,  12, 189, 177,  74,
285
  120, 136, 149, 139, 227,  99, 232, 109, 233, 203, 213, 254,  59,   0,  29,  57,
286
  242, 239, 183,  14, 102,  88, 208, 228, 166, 119, 114, 248, 235, 117,  75,  10,
287
   49,  68,  80, 180, 143, 237,  31,  26, 219, 153, 141,  51, 159,  17, 131,  20 };
288
289
PHP_HASH_API void PHP_MD2InitArgs(PHP_MD2_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
290
0
{
291
0
  memset(context, 0, sizeof(PHP_MD2_CTX));
292
0
}
293
294
static void MD2_Transform(PHP_MD2_CTX *context, const unsigned char *block)
295
0
{
296
0
  unsigned char i,j,t = 0;
297
298
0
  for(i = 0; i < 16; i++) {
299
0
    context->state[16+i] = block[i];
300
0
    context->state[32+i] = (context->state[16+i] ^ context->state[i]);
301
0
  }
302
303
0
  for(i = 0; i < 18; i++) {
304
0
    for(j = 0; j < 48; j++) {
305
0
      t = context->state[j] = context->state[j] ^ MD2_S[t];
306
0
    }
307
0
    t += i;
308
0
  }
309
310
  /* Update checksum -- must be after transform to avoid fouling up last message block */
311
0
  t = context->checksum[15];
312
0
  for(i = 0; i < 16; i++) {
313
0
    t = context->checksum[i] ^= MD2_S[block[i] ^ t];
314
0
  }
315
0
}
316
317
PHP_HASH_API void PHP_MD2Update(PHP_MD2_CTX *context, const unsigned char *buf, size_t len)
318
0
{
319
0
  const unsigned char *p = buf, *e = buf + len;
320
321
0
  if (context->in_buffer) {
322
0
    if (context->in_buffer + len < 16) {
323
      /* Not enough for block, just pass into buffer */
324
0
      memcpy(context->buffer + context->in_buffer, p, len);
325
0
      context->in_buffer += (char) len;
326
0
      return;
327
0
    }
328
    /* Put buffered data together with inbound for a single block */
329
0
    memcpy(context->buffer + context->in_buffer, p, 16 - context->in_buffer);
330
0
    MD2_Transform(context, context->buffer);
331
0
    p += 16 - context->in_buffer;
332
0
    context->in_buffer = 0;
333
0
  }
334
335
  /* Process as many whole blocks as remain */
336
0
  while ((p + 16) <= e) {
337
0
    MD2_Transform(context, p);
338
0
    p += 16;
339
0
  }
340
341
  /* Copy remaining data to buffer */
342
0
  if (p < e) {
343
0
    memcpy(context->buffer, p, e - p);
344
0
    context->in_buffer = (char) (e - p);
345
0
  }
346
0
}
347
348
PHP_HASH_API void PHP_MD2Final(unsigned char output[16], PHP_MD2_CTX *context)
349
0
{
350
0
  memset(context->buffer + context->in_buffer, 16 - context->in_buffer, 16 - context->in_buffer);
351
0
  MD2_Transform(context, context->buffer);
352
0
  MD2_Transform(context, context->checksum);
353
354
0
  memcpy(output, context->state, 16);
355
0
}
356
357
static hash_spec_result php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
358
0
{
359
0
  PHP_MD2_CTX *ctx = (PHP_MD2_CTX *) hash->context;
360
0
  hash_spec_result r = HASH_SPEC_FAILURE;
361
0
  if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
362
0
    && (r = php_hash_unserialize_spec(hash, zv, PHP_MD2_SPEC)) == HASH_SPEC_SUCCESS
363
0
    && (unsigned char) ctx->in_buffer < sizeof(ctx->buffer)) {
364
0
    return HASH_SPEC_SUCCESS;
365
0
  }
366
367
0
    return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
368
0
}