Coverage Report

Created: 2026-02-09 07:07

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