Coverage Report

Created: 2025-12-14 06:06

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