Coverage Report

Created: 2025-12-14 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/standard/md5.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
   | Author: Alexander Peslyak (Solar Designer) <solar at openwall.com>   |
14
   |         Lachlan Roche                                                |
15
   |         Alessandro Astarita <aleast@capri.it>                        |
16
   +----------------------------------------------------------------------+
17
*/
18
19
#include "php.h"
20
#include "md5.h"
21
22
PHPAPI void make_digest(char *md5str, const unsigned char *digest)
23
0
{
24
0
  make_digest_ex(md5str, digest, 16);
25
0
}
26
27
PHPAPI void make_digest_ex(char *md5str, const unsigned char *digest, size_t len)
28
489
{
29
489
  static const char hexits[17] = "0123456789abcdef";
30
31
8.31k
  for (size_t i = 0; i < len; i++) {
32
7.82k
    md5str[i * 2]       = hexits[digest[i] >> 4];
33
7.82k
    md5str[(i * 2) + 1] = hexits[digest[i] &  0x0F];
34
7.82k
  }
35
489
  md5str[len * 2] = '\0';
36
489
}
37
38
/* Calculate the md5 hash of a string */
39
PHP_FUNCTION(md5)
40
489
{
41
489
  zend_string *arg;
42
489
  PHP_MD5_CTX context;
43
489
  unsigned char digest[16];
44
489
  bool raw_output = false;
45
46
1.46k
  ZEND_PARSE_PARAMETERS_START(1, 2)
47
1.95k
    Z_PARAM_STR(arg)
48
489
    Z_PARAM_OPTIONAL
49
978
    Z_PARAM_BOOL(raw_output)
50
489
  ZEND_PARSE_PARAMETERS_END();
51
52
489
  PHP_MD5Init(&context);
53
489
  PHP_MD5Update(&context, ZSTR_VAL(arg), ZSTR_LEN(arg));
54
489
  PHP_MD5Final(digest, &context);
55
489
  if (raw_output) {
56
0
    RETURN_STRINGL((char *) digest, 16);
57
489
  } else {
58
489
    RETVAL_NEW_STR(zend_string_alloc(32, 0));
59
489
    make_digest_ex(Z_STRVAL_P(return_value), digest, 16);
60
489
  }
61
62
489
}
63
64
/* Calculate the md5 hash of given filename */
65
PHP_FUNCTION(md5_file)
66
0
{
67
0
  char          *arg;
68
0
  size_t           arg_len;
69
0
  bool raw_output = false;
70
0
  unsigned char buf[1024];
71
0
  unsigned char digest[16];
72
0
  PHP_MD5_CTX   context;
73
0
  ssize_t       n;
74
0
  php_stream    *stream;
75
76
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
77
0
    Z_PARAM_PATH(arg, arg_len)
78
0
    Z_PARAM_OPTIONAL
79
0
    Z_PARAM_BOOL(raw_output)
80
0
  ZEND_PARSE_PARAMETERS_END();
81
82
0
  stream = php_stream_open_wrapper(arg, "rb", REPORT_ERRORS, NULL);
83
0
  if (!stream) {
84
0
    RETURN_FALSE;
85
0
  }
86
87
0
  PHP_MD5Init(&context);
88
89
0
  while ((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) {
90
0
    PHP_MD5Update(&context, buf, n);
91
0
  }
92
93
  /* XXX this probably can be improved with some number of retries */
94
0
  if (!php_stream_eof(stream)) {
95
0
    php_stream_close(stream);
96
0
    PHP_MD5Final(digest, &context);
97
98
0
    RETURN_FALSE;
99
0
  }
100
101
0
  php_stream_close(stream);
102
103
0
  PHP_MD5Final(digest, &context);
104
105
0
  if (raw_output) {
106
0
    RETURN_STRINGL((char *) digest, 16);
107
0
  } else {
108
0
    RETVAL_NEW_STR(zend_string_alloc(32, 0));
109
0
    make_digest_ex(Z_STRVAL_P(return_value), digest, 16);
110
0
  }
111
0
}
112
113
/*
114
 * This is an OpenSSL-compatible implementation of the RSA Data Security,
115
 * Inc. MD5 Message-Digest Algorithm (RFC 1321).
116
 *
117
 * Written by Solar Designer <solar at openwall.com> in 2001, and placed
118
 * in the public domain.  There's absolutely no warranty.
119
 *
120
 * This differs from Colin Plumb's older public domain implementation in
121
 * that no 32-bit integer data type is required, there's no compile-time
122
 * endianness configuration, and the function prototypes match OpenSSL's.
123
 * The primary goals are portability and ease of use.
124
 *
125
 * This implementation is meant to be fast, but not as fast as possible.
126
 * Some known optimizations are not included to reduce source code size
127
 * and avoid compile-time configuration.
128
 */
129
130
#include <string.h>
131
132
/*
133
 * The basic MD5 functions.
134
 *
135
 * F and G are optimized compared to their RFC 1321 definitions for
136
 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
137
 * implementation.
138
 */
139
345k
#define F(x, y, z)      ((z) ^ ((x) & ((y) ^ (z))))
140
345k
#define G(x, y, z)      ((y) ^ ((z) & ((x) ^ (y))))
141
345k
#define H(x, y, z)      ((x) ^ (y) ^ (z))
142
345k
#define I(x, y, z)      ((y) ^ ((x) | ~(z)))
143
144
/*
145
 * The MD5 transformation for all four rounds.
146
 */
147
#define STEP(f, a, b, c, d, x, t, s) \
148
1.38M
  (a) += f((b), (c), (d)) + (x) + (t); \
149
1.38M
  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
150
1.38M
  (a) += (b);
151
152
/*
153
 * SET reads 4 input bytes in little-endian byte order and stores them
154
 * in a properly aligned word in host byte order.
155
 *
156
 * The check for little-endian architectures that tolerate unaligned
157
 * memory accesses is just an optimization.  Nothing will break if it
158
 * doesn't work.
159
 */
160
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
161
typedef ZEND_SET_ALIGNED(1, uint32_t unaligned_uint32_t);
162
# define SET(n) \
163
  (*(unaligned_uint32_t *)&ptr[(n) * 4])
164
# define GET(n) \
165
  SET(n)
166
#else
167
# define SET(n) \
168
  (ctx->block[(n)] = \
169
  (uint32_t)ptr[(n) * 4] | \
170
  ((uint32_t)ptr[(n) * 4 + 1] << 8) | \
171
  ((uint32_t)ptr[(n) * 4 + 2] << 16) | \
172
  ((uint32_t)ptr[(n) * 4 + 3] << 24))
173
# define GET(n) \
174
  (ctx->block[(n)])
175
#endif
176
177
/*
178
 * This processes one or more 64-byte data blocks, but does NOT update
179
 * the bit counters.  There are no alignment requirements.
180
 */
181
static const void *body(PHP_MD5_CTX *ctx, const void *data, size_t size)
182
619
{
183
619
  const unsigned char *ptr;
184
619
  uint32_t a, b, c, d;
185
619
  uint32_t saved_a, saved_b, saved_c, saved_d;
186
187
619
  ptr = data;
188
189
619
  a = ctx->a;
190
619
  b = ctx->b;
191
619
  c = ctx->c;
192
619
  d = ctx->d;
193
194
21.5k
  do {
195
21.5k
    saved_a = a;
196
21.5k
    saved_b = b;
197
21.5k
    saved_c = c;
198
21.5k
    saved_d = d;
199
200
/* Round 1 */
201
21.5k
    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
202
21.5k
    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
203
21.5k
    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
204
21.5k
    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
205
21.5k
    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
206
21.5k
    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
207
21.5k
    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
208
21.5k
    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
209
21.5k
    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
210
21.5k
    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
211
21.5k
    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
212
21.5k
    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
213
21.5k
    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
214
21.5k
    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
215
21.5k
    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
216
21.5k
    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
217
218
/* Round 2 */
219
21.5k
    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
220
21.5k
    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
221
21.5k
    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
222
21.5k
    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
223
21.5k
    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
224
21.5k
    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
225
21.5k
    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
226
21.5k
    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
227
21.5k
    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
228
21.5k
    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
229
21.5k
    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
230
21.5k
    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
231
21.5k
    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
232
21.5k
    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
233
21.5k
    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
234
21.5k
    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
235
236
/* Round 3 */
237
21.5k
    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
238
21.5k
    STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
239
21.5k
    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
240
21.5k
    STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
241
21.5k
    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
242
21.5k
    STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
243
21.5k
    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
244
21.5k
    STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
245
21.5k
    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
246
21.5k
    STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
247
21.5k
    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
248
21.5k
    STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
249
21.5k
    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
250
21.5k
    STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
251
21.5k
    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
252
21.5k
    STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
253
254
/* Round 4 */
255
21.5k
    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
256
21.5k
    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
257
21.5k
    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
258
21.5k
    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
259
21.5k
    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
260
21.5k
    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
261
21.5k
    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
262
21.5k
    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
263
21.5k
    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
264
21.5k
    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
265
21.5k
    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
266
21.5k
    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
267
21.5k
    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
268
21.5k
    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
269
21.5k
    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
270
21.5k
    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
271
272
21.5k
    a += saved_a;
273
21.5k
    b += saved_b;
274
21.5k
    c += saved_c;
275
21.5k
    d += saved_d;
276
277
21.5k
    ptr += 64;
278
21.5k
  } while (size -= 64);
279
280
619
  ctx->a = a;
281
619
  ctx->b = b;
282
619
  ctx->c = c;
283
619
  ctx->d = d;
284
285
619
  return ptr;
286
619
}
287
288
PHPAPI void PHP_MD5InitArgs(PHP_MD5_CTX *ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args)
289
536
{
290
536
  ctx->a = 0x67452301;
291
536
  ctx->b = 0xefcdab89;
292
536
  ctx->c = 0x98badcfe;
293
536
  ctx->d = 0x10325476;
294
295
536
  ctx->lo = 0;
296
536
  ctx->hi = 0;
297
536
}
298
299
PHPAPI void PHP_MD5Update(PHP_MD5_CTX *ctx, const void *data, size_t size)
300
663
{
301
663
  uint32_t saved_lo;
302
663
  uint32_t used, free;
303
304
663
  saved_lo = ctx->lo;
305
663
  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) {
306
23
    ctx->hi++;
307
23
  }
308
663
  ctx->hi += size >> 29;
309
310
663
  used = saved_lo & 0x3f;
311
312
663
  if (used) {
313
141
    free = 64 - used;
314
315
141
    if (size < free) {
316
97
      memcpy(&ctx->buffer[used], data, size);
317
97
      return;
318
97
    }
319
320
44
    memcpy(&ctx->buffer[used], data, free);
321
44
    data = (unsigned char *)data + free;
322
44
    size -= free;
323
44
    body(ctx, ctx->buffer, 64);
324
44
  }
325
326
566
  if (size >= 64) {
327
32
    data = body(ctx, data, size & ~(size_t)0x3f);
328
32
    size &= 0x3f;
329
32
  }
330
331
566
  memcpy(ctx->buffer, data, size);
332
566
}
333
334
PHPAPI void PHP_MD5Final(unsigned char *result, PHP_MD5_CTX *ctx)
335
535
{
336
535
  uint32_t used, free;
337
338
535
  used = ctx->lo & 0x3f;
339
340
535
  ctx->buffer[used++] = 0x80;
341
342
535
  free = 64 - used;
343
344
535
  if (free < 8) {
345
8
    memset(&ctx->buffer[used], 0, free);
346
8
    body(ctx, ctx->buffer, 64);
347
8
    used = 0;
348
8
    free = 64;
349
8
  }
350
351
535
  memset(&ctx->buffer[used], 0, free - 8);
352
353
535
  ctx->lo <<= 3;
354
535
  ctx->buffer[56] = ctx->lo;
355
535
  ctx->buffer[57] = ctx->lo >> 8;
356
535
  ctx->buffer[58] = ctx->lo >> 16;
357
535
  ctx->buffer[59] = ctx->lo >> 24;
358
535
  ctx->buffer[60] = ctx->hi;
359
535
  ctx->buffer[61] = ctx->hi >> 8;
360
535
  ctx->buffer[62] = ctx->hi >> 16;
361
535
  ctx->buffer[63] = ctx->hi >> 24;
362
363
535
  body(ctx, ctx->buffer, 64);
364
365
535
  result[0] = ctx->a;
366
535
  result[1] = ctx->a >> 8;
367
535
  result[2] = ctx->a >> 16;
368
535
  result[3] = ctx->a >> 24;
369
535
  result[4] = ctx->b;
370
535
  result[5] = ctx->b >> 8;
371
535
  result[6] = ctx->b >> 16;
372
535
  result[7] = ctx->b >> 24;
373
535
  result[8] = ctx->c;
374
535
  result[9] = ctx->c >> 8;
375
535
  result[10] = ctx->c >> 16;
376
535
  result[11] = ctx->c >> 24;
377
535
  result[12] = ctx->d;
378
535
  result[13] = ctx->d >> 8;
379
535
  result[14] = ctx->d >> 16;
380
535
  result[15] = ctx->d >> 24;
381
382
535
  ZEND_SECURE_ZERO(ctx, sizeof(*ctx));
383
535
}