Coverage Report

Created: 2026-01-18 06:47

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