Coverage Report

Created: 2025-06-13 06:43

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