Coverage Report

Created: 2025-11-16 06:23

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
162
{
82
162
  unsigned int i, j;
83
84
648
  for (i = 0, j = 0; j < len; i++, j += 4) {
85
486
    output[j] = (unsigned char) (input[i] & 0xff);
86
486
    output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
87
486
    output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
88
486
    output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
89
486
  }
90
162
}
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
54.0k
{
99
54.0k
  unsigned int i, j;
100
101
918k
  for (i = 0, j = 0; j < len; i++, j += 4)
102
864k
    output[i] = ((uint32_t) input[j]) | (((uint32_t) input[j + 1]) << 8) |
103
864k
      (((uint32_t) input[j + 2]) << 16) | (((uint32_t) input[j + 3]) << 24);
104
54.0k
}
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
2.59M
#define ROTL32(s,v)       (((v) << (s)) | ((v) >> (32 - (s))))
114
115
864k
#define MD4_R1(a,b,c,d,k,s)   a = ROTL32(s, a + MD4_F(b,c,d) + x[k])
116
864k
#define MD4_R2(a,b,c,d,k,s)   a = ROTL32(s, a + MD4_G(b,c,d) + x[k] + 0x5A827999)
117
864k
#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
54.0k
{
121
54.0k
  uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
122
123
54.0k
  Decode(x, block, 64);
124
125
  /* Round 1 */
126
54.0k
  MD4_R1(a,b,c,d, 0, 3);
127
54.0k
  MD4_R1(d,a,b,c, 1, 7);
128
54.0k
  MD4_R1(c,d,a,b, 2,11);
129
54.0k
  MD4_R1(b,c,d,a, 3,19);
130
54.0k
  MD4_R1(a,b,c,d, 4, 3);
131
54.0k
  MD4_R1(d,a,b,c, 5, 7);
132
54.0k
  MD4_R1(c,d,a,b, 6,11);
133
54.0k
  MD4_R1(b,c,d,a, 7,19);
134
54.0k
  MD4_R1(a,b,c,d, 8, 3);
135
54.0k
  MD4_R1(d,a,b,c, 9, 7);
136
54.0k
  MD4_R1(c,d,a,b,10,11);
137
54.0k
  MD4_R1(b,c,d,a,11,19);
138
54.0k
  MD4_R1(a,b,c,d,12, 3);
139
54.0k
  MD4_R1(d,a,b,c,13, 7);
140
54.0k
  MD4_R1(c,d,a,b,14,11);
141
54.0k
  MD4_R1(b,c,d,a,15,19);
142
143
  /* Round 2 */
144
54.0k
  MD4_R2(a,b,c,d, 0, 3);
145
54.0k
  MD4_R2(d,a,b,c, 4, 5);
146
54.0k
  MD4_R2(c,d,a,b, 8, 9);
147
54.0k
  MD4_R2(b,c,d,a,12,13);
148
54.0k
  MD4_R2(a,b,c,d, 1, 3);
149
54.0k
  MD4_R2(d,a,b,c, 5, 5);
150
54.0k
  MD4_R2(c,d,a,b, 9, 9);
151
54.0k
  MD4_R2(b,c,d,a,13,13);
152
54.0k
  MD4_R2(a,b,c,d, 2, 3);
153
54.0k
  MD4_R2(d,a,b,c, 6, 5);
154
54.0k
  MD4_R2(c,d,a,b,10, 9);
155
54.0k
  MD4_R2(b,c,d,a,14,13);
156
54.0k
  MD4_R2(a,b,c,d, 3, 3);
157
54.0k
  MD4_R2(d,a,b,c, 7, 5);
158
54.0k
  MD4_R2(c,d,a,b,11, 9);
159
54.0k
  MD4_R2(b,c,d,a,15,13);
160
161
  /* Round 3 */
162
54.0k
  MD4_R3(a,b,c,d, 0, 3);
163
54.0k
  MD4_R3(d,a,b,c, 8, 9);
164
54.0k
  MD4_R3(c,d,a,b, 4,11);
165
54.0k
  MD4_R3(b,c,d,a,12,15);
166
54.0k
  MD4_R3(a,b,c,d, 2, 3);
167
54.0k
  MD4_R3(d,a,b,c,10, 9);
168
54.0k
  MD4_R3(c,d,a,b, 6,11);
169
54.0k
  MD4_R3(b,c,d,a,14,15);
170
54.0k
  MD4_R3(a,b,c,d, 1, 3);
171
54.0k
  MD4_R3(d,a,b,c, 9, 9);
172
54.0k
  MD4_R3(c,d,a,b, 5,11);
173
54.0k
  MD4_R3(b,c,d,a,13,15);
174
54.0k
  MD4_R3(a,b,c,d, 3, 3);
175
54.0k
  MD4_R3(d,a,b,c,11, 9);
176
54.0k
  MD4_R3(c,d,a,b, 7,11);
177
54.0k
  MD4_R3(b,c,d,a,15,15);
178
179
54.0k
  state[0] += a;
180
54.0k
  state[1] += b;
181
54.0k
  state[2] += c;
182
54.0k
  state[3] += d;
183
54.0k
}
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
82
{
190
82
  context->count[0] = context->count[1] = 0;
191
  /* Load magic initialization constants.
192
   */
193
82
  context->state[0] = 0x67452301;
194
82
  context->state[1] = 0xefcdab89;
195
82
  context->state[2] = 0x98badcfe;
196
82
  context->state[3] = 0x10325476;
197
82
}
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
243
{
207
243
  unsigned int index, partLen;
208
243
  size_t i;
209
210
  /* Compute number of bytes mod 64 */
211
243
  index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
212
213
  /* Update number of bits */
214
243
  if ((context->count[0] += ((uint32_t) inputLen << 3))
215
243
    < ((uint32_t) inputLen << 3))
216
11
    context->count[1]++;
217
243
  context->count[1] += (uint32_t) (inputLen >> 29);
218
219
243
  partLen = 64 - index;
220
221
  /* Transform as many times as possible.
222
   */
223
243
  if (inputLen >= partLen) {
224
172
    memcpy((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen);
225
172
    MD4Transform(context->state, context->buffer);
226
227
54.0k
    for (i = partLen; i + 63 < inputLen; i += 64) {
228
53.8k
      MD4Transform(context->state, &input[i]);
229
53.8k
    }
230
231
172
    index = 0;
232
172
  } else {
233
71
    i = 0;
234
71
  }
235
236
  /* Buffer remaining input */
237
243
  memcpy((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], inputLen - i);
238
243
}
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
81
{
247
81
  unsigned char bits[8];
248
81
  unsigned int index, padLen;
249
250
  /* Save number of bits */
251
81
  Encode(bits, context->count, 8);
252
253
  /* Pad out to 56 mod 64.
254
   */
255
81
  index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
256
81
  padLen = (index < 56) ? (56 - index) : (120 - index);
257
81
  PHP_MD4Update(context, PADDING, padLen);
258
259
  /* Append length (before padding) */
260
81
  PHP_MD4Update(context, bits, 8);
261
262
  /* Store state in digest */
263
81
  Encode(digest, context->state, 16);
264
265
  /* Zeroize sensitive information.
266
   */
267
81
  ZEND_SECURE_ZERO((unsigned char*) context, sizeof(*context));
268
81
}
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
33
{
293
33
  memset(context, 0, sizeof(PHP_MD2_CTX));
294
33
}
295
296
static void MD2_Transform(PHP_MD2_CTX *context, const unsigned char *block)
297
1.90k
{
298
1.90k
  unsigned char i,j,t = 0;
299
300
32.3k
  for(i = 0; i < 16; i++) {
301
30.4k
    context->state[16+i] = block[i];
302
30.4k
    context->state[32+i] = (context->state[16+i] ^ context->state[i]);
303
30.4k
  }
304
305
36.1k
  for(i = 0; i < 18; i++) {
306
1.67M
    for(j = 0; j < 48; j++) {
307
1.64M
      t = context->state[j] = context->state[j] ^ MD2_S[t];
308
1.64M
    }
309
34.2k
    t += i;
310
34.2k
  }
311
312
  /* Update checksum -- must be after transform to avoid fouling up last message block */
313
1.90k
  t = context->checksum[15];
314
32.3k
  for(i = 0; i < 16; i++) {
315
30.4k
    t = context->checksum[i] ^= MD2_S[block[i] ^ t];
316
30.4k
  }
317
1.90k
}
318
319
PHP_HASH_API void PHP_MD2Update(PHP_MD2_CTX *context, const unsigned char *buf, size_t len)
320
25
{
321
25
  const unsigned char *p = buf, *e = buf + len;
322
323
25
  if (context->in_buffer) {
324
2
    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
1
    memcpy(context->buffer + context->in_buffer, p, 16 - context->in_buffer);
332
1
    MD2_Transform(context, context->buffer);
333
1
    p += 16 - context->in_buffer;
334
1
    context->in_buffer = 0;
335
1
  }
336
337
  /* Process as many whole blocks as remain */
338
1.87k
  while ((p + 16) <= e) {
339
1.84k
    MD2_Transform(context, p);
340
1.84k
    p += 16;
341
1.84k
  }
342
343
  /* Copy remaining data to buffer */
344
24
  if (p < e) {
345
6
    memcpy(context->buffer, p, e - p);
346
6
    context->in_buffer = (char) (e - p);
347
6
  }
348
24
}
349
350
PHP_HASH_API void PHP_MD2Final(unsigned char output[16], PHP_MD2_CTX *context)
351
25
{
352
25
  memset(context->buffer + context->in_buffer, 16 - context->in_buffer, 16 - context->in_buffer);
353
25
  MD2_Transform(context, context->buffer);
354
25
  MD2_Transform(context, context->checksum);
355
356
25
  memcpy(output, context->state, 16);
357
25
}
358
359
static hash_spec_result php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv)
360
33
{
361
33
  PHP_MD2_CTX *ctx = (PHP_MD2_CTX *) hash->context;
362
33
  hash_spec_result r = HASH_SPEC_FAILURE;
363
33
  if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
364
31
    && (r = php_hash_unserialize_spec(hash, zv, PHP_MD2_SPEC)) == HASH_SPEC_SUCCESS
365
26
    && (unsigned char) ctx->in_buffer < sizeof(ctx->buffer)) {
366
25
    return HASH_SPEC_SUCCESS;
367
25
  }
368
369
8
    return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
370
33
}