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