Coverage Report

Created: 2025-07-23 06:33

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