Coverage Report

Created: 2026-02-14 06:52

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