Coverage Report

Created: 2025-11-16 06:23

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