Coverage Report

Created: 2025-09-27 06:26

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