Coverage Report

Created: 2025-09-27 06:26

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