Coverage Report

Created: 2025-12-14 06:06

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
0
{
29
0
  static const char hexits[17] = "0123456789abcdef";
30
31
0
  for (size_t i = 0; i < len; i++) {
32
0
    md5str[i * 2]       = hexits[digest[i] >> 4];
33
0
    md5str[(i * 2) + 1] = hexits[digest[i] &  0x0F];
34
0
  }
35
0
  md5str[len * 2] = '\0';
36
0
}
37
38
/* Calculate the md5 hash of a string */
39
PHP_FUNCTION(md5)
40
0
{
41
0
  zend_string *arg;
42
0
  PHP_MD5_CTX context;
43
0
  unsigned char digest[16];
44
0
  bool raw_output = false;
45
46
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
47
0
    Z_PARAM_STR(arg)
48
0
    Z_PARAM_OPTIONAL
49
0
    Z_PARAM_BOOL(raw_output)
50
0
  ZEND_PARSE_PARAMETERS_END();
51
52
0
  PHP_MD5Init(&context);
53
0
  PHP_MD5Update(&context, ZSTR_VAL(arg), ZSTR_LEN(arg));
54
0
  PHP_MD5Final(digest, &context);
55
0
  if (raw_output) {
56
0
    RETURN_STRINGL((char *) digest, 16);
57
0
  } else {
58
0
    RETVAL_NEW_STR(zend_string_alloc(32, 0));
59
0
    make_digest_ex(Z_STRVAL_P(return_value), digest, 16);
60
0
  }
61
62
0
}
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
336k
#define F(x, y, z)      ((z) ^ ((x) & ((y) ^ (z))))
140
336k
#define G(x, y, z)      ((y) ^ ((z) & ((x) ^ (y))))
141
336k
#define H(x, y, z)      ((x) ^ (y) ^ (z))
142
336k
#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.34M
  (a) += f((b), (c), (d)) + (x) + (t); \
149
1.34M
  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
150
1.34M
  (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
93
{
183
93
  const unsigned char *ptr;
184
93
  uint32_t a, b, c, d;
185
93
  uint32_t saved_a, saved_b, saved_c, saved_d;
186
187
93
  ptr = data;
188
189
93
  a = ctx->a;
190
93
  b = ctx->b;
191
93
  c = ctx->c;
192
93
  d = ctx->d;
193
194
21.0k
  do {
195
21.0k
    saved_a = a;
196
21.0k
    saved_b = b;
197
21.0k
    saved_c = c;
198
21.0k
    saved_d = d;
199
200
/* Round 1 */
201
21.0k
    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
202
21.0k
    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
203
21.0k
    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
204
21.0k
    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
205
21.0k
    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
206
21.0k
    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
207
21.0k
    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
208
21.0k
    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
209
21.0k
    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
210
21.0k
    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
211
21.0k
    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
212
21.0k
    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
213
21.0k
    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
214
21.0k
    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
215
21.0k
    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
216
21.0k
    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
217
218
/* Round 2 */
219
21.0k
    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
220
21.0k
    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
221
21.0k
    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
222
21.0k
    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
223
21.0k
    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
224
21.0k
    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
225
21.0k
    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
226
21.0k
    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
227
21.0k
    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
228
21.0k
    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
229
21.0k
    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
230
21.0k
    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
231
21.0k
    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
232
21.0k
    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
233
21.0k
    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
234
21.0k
    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
235
236
/* Round 3 */
237
21.0k
    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
238
21.0k
    STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
239
21.0k
    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
240
21.0k
    STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
241
21.0k
    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
242
21.0k
    STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
243
21.0k
    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
244
21.0k
    STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
245
21.0k
    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
246
21.0k
    STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
247
21.0k
    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
248
21.0k
    STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
249
21.0k
    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
250
21.0k
    STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
251
21.0k
    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
252
21.0k
    STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
253
254
/* Round 4 */
255
21.0k
    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
256
21.0k
    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
257
21.0k
    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
258
21.0k
    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
259
21.0k
    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
260
21.0k
    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
261
21.0k
    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
262
21.0k
    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
263
21.0k
    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
264
21.0k
    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
265
21.0k
    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
266
21.0k
    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
267
21.0k
    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
268
21.0k
    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
269
21.0k
    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
270
21.0k
    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
271
272
21.0k
    a += saved_a;
273
21.0k
    b += saved_b;
274
21.0k
    c += saved_c;
275
21.0k
    d += saved_d;
276
277
21.0k
    ptr += 64;
278
21.0k
  } while (size -= 64);
279
280
93
  ctx->a = a;
281
93
  ctx->b = b;
282
93
  ctx->c = c;
283
93
  ctx->d = d;
284
285
93
  return ptr;
286
93
}
287
288
PHPAPI void PHP_MD5InitArgs(PHP_MD5_CTX *ctx, ZEND_ATTRIBUTE_UNUSED HashTable *args)
289
33
{
290
33
  ctx->a = 0x67452301;
291
33
  ctx->b = 0xefcdab89;
292
33
  ctx->c = 0x98badcfe;
293
33
  ctx->d = 0x10325476;
294
295
33
  ctx->lo = 0;
296
33
  ctx->hi = 0;
297
33
}
298
299
PHPAPI void PHP_MD5Update(PHP_MD5_CTX *ctx, const void *data, size_t size)
300
48
{
301
48
  uint32_t saved_lo;
302
48
  uint32_t used, free;
303
304
48
  saved_lo = ctx->lo;
305
48
  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) {
306
23
    ctx->hi++;
307
23
  }
308
48
  ctx->hi += size >> 29;
309
310
48
  used = saved_lo & 0x3f;
311
312
48
  if (used) {
313
43
    free = 64 - used;
314
315
43
    if (size < free) {
316
13
      memcpy(&ctx->buffer[used], data, size);
317
13
      return;
318
13
    }
319
320
30
    memcpy(&ctx->buffer[used], data, free);
321
30
    data = (unsigned char *)data + free;
322
30
    size -= free;
323
30
    body(ctx, ctx->buffer, 64);
324
30
  }
325
326
35
  if (size >= 64) {
327
26
    data = body(ctx, data, size & ~(size_t)0x3f);
328
26
    size &= 0x3f;
329
26
  }
330
331
35
  memcpy(ctx->buffer, data, size);
332
35
}
333
334
PHPAPI void PHP_MD5Final(unsigned char *result, PHP_MD5_CTX *ctx)
335
32
{
336
32
  uint32_t used, free;
337
338
32
  used = ctx->lo & 0x3f;
339
340
32
  ctx->buffer[used++] = 0x80;
341
342
32
  free = 64 - used;
343
344
32
  if (free < 8) {
345
5
    memset(&ctx->buffer[used], 0, free);
346
5
    body(ctx, ctx->buffer, 64);
347
5
    used = 0;
348
5
    free = 64;
349
5
  }
350
351
32
  memset(&ctx->buffer[used], 0, free - 8);
352
353
32
  ctx->lo <<= 3;
354
32
  ctx->buffer[56] = ctx->lo;
355
32
  ctx->buffer[57] = ctx->lo >> 8;
356
32
  ctx->buffer[58] = ctx->lo >> 16;
357
32
  ctx->buffer[59] = ctx->lo >> 24;
358
32
  ctx->buffer[60] = ctx->hi;
359
32
  ctx->buffer[61] = ctx->hi >> 8;
360
32
  ctx->buffer[62] = ctx->hi >> 16;
361
32
  ctx->buffer[63] = ctx->hi >> 24;
362
363
32
  body(ctx, ctx->buffer, 64);
364
365
32
  result[0] = ctx->a;
366
32
  result[1] = ctx->a >> 8;
367
32
  result[2] = ctx->a >> 16;
368
32
  result[3] = ctx->a >> 24;
369
32
  result[4] = ctx->b;
370
32
  result[5] = ctx->b >> 8;
371
32
  result[6] = ctx->b >> 16;
372
32
  result[7] = ctx->b >> 24;
373
32
  result[8] = ctx->c;
374
32
  result[9] = ctx->c >> 8;
375
32
  result[10] = ctx->c >> 16;
376
32
  result[11] = ctx->c >> 24;
377
32
  result[12] = ctx->d;
378
32
  result[13] = ctx->d >> 8;
379
32
  result[14] = ctx->d >> 16;
380
32
  result[15] = ctx->d >> 24;
381
382
32
  ZEND_SECURE_ZERO(ctx, sizeof(*ctx));
383
32
}