Coverage Report

Created: 2025-12-14 06:09

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