Coverage Report

Created: 2026-04-01 06:49

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