1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Alexander Peslyak (Solar Designer) <solar at openwall.com> |
16 | Lachlan Roche |
17 | Alessandro Astarita <aleast@capri.it> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include "php.h"
22 #include "md5.h"
23
make_digest(char * md5str,const unsigned char * digest)24 PHPAPI void make_digest(char *md5str, const unsigned char *digest) /* {{{ */
25 {
26 make_digest_ex(md5str, digest, 16);
27 }
28 /* }}} */
29
make_digest_ex(char * md5str,const unsigned char * digest,int len)30 PHPAPI void make_digest_ex(char *md5str, const unsigned char *digest, int len) /* {{{ */
31 {
32 static const char hexits[17] = "0123456789abcdef";
33 int i;
34
35 for (i = 0; i < len; i++) {
36 md5str[i * 2] = hexits[digest[i] >> 4];
37 md5str[(i * 2) + 1] = hexits[digest[i] & 0x0F];
38 }
39 md5str[len * 2] = '\0';
40 }
41 /* }}} */
42
43 /* {{{ proto string md5(string str, [ bool raw_output])
44 Calculate the md5 hash of a string */
PHP_NAMED_FUNCTION(php_if_md5)45 PHP_NAMED_FUNCTION(php_if_md5)
46 {
47 zend_string *arg;
48 zend_bool raw_output = 0;
49 PHP_MD5_CTX context;
50 unsigned char digest[16];
51
52 ZEND_PARSE_PARAMETERS_START(1, 2)
53 Z_PARAM_STR(arg)
54 Z_PARAM_OPTIONAL
55 Z_PARAM_BOOL(raw_output)
56 ZEND_PARSE_PARAMETERS_END();
57
58 PHP_MD5Init(&context);
59 PHP_MD5Update(&context, ZSTR_VAL(arg), ZSTR_LEN(arg));
60 PHP_MD5Final(digest, &context);
61 if (raw_output) {
62 RETURN_STRINGL((char *) digest, 16);
63 } else {
64 RETVAL_NEW_STR(zend_string_alloc(32, 0));
65 make_digest_ex(Z_STRVAL_P(return_value), digest, 16);
66 }
67
68 }
69 /* }}} */
70
71 /* {{{ proto string md5_file(string filename [, bool raw_output])
72 Calculate the md5 hash of given filename */
PHP_NAMED_FUNCTION(php_if_md5_file)73 PHP_NAMED_FUNCTION(php_if_md5_file)
74 {
75 char *arg;
76 size_t arg_len;
77 zend_bool raw_output = 0;
78 unsigned char buf[1024];
79 unsigned char digest[16];
80 PHP_MD5_CTX context;
81 size_t n;
82 php_stream *stream;
83
84 ZEND_PARSE_PARAMETERS_START(1, 2)
85 Z_PARAM_PATH(arg, arg_len)
86 Z_PARAM_OPTIONAL
87 Z_PARAM_BOOL(raw_output)
88 ZEND_PARSE_PARAMETERS_END();
89
90 stream = php_stream_open_wrapper(arg, "rb", REPORT_ERRORS, NULL);
91 if (!stream) {
92 RETURN_FALSE;
93 }
94
95 PHP_MD5Init(&context);
96
97 while ((n = php_stream_read(stream, (char*)buf, sizeof(buf))) > 0) {
98 PHP_MD5Update(&context, buf, n);
99 }
100
101 /* XXX this probably can be improved with some number of retries */
102 if (!php_stream_eof(stream)) {
103 php_stream_close(stream);
104 PHP_MD5Final(digest, &context);
105
106 RETURN_FALSE;
107 }
108
109 php_stream_close(stream);
110
111 PHP_MD5Final(digest, &context);
112
113 if (raw_output) {
114 RETURN_STRINGL((char *) digest, 16);
115 } else {
116 RETVAL_NEW_STR(zend_string_alloc(32, 0));
117 make_digest_ex(Z_STRVAL_P(return_value), digest, 16);
118 }
119 }
120 /* }}} */
121
122 /*
123 * This is an OpenSSL-compatible implementation of the RSA Data Security,
124 * Inc. MD5 Message-Digest Algorithm (RFC 1321).
125 *
126 * Written by Solar Designer <solar at openwall.com> in 2001, and placed
127 * in the public domain. There's absolutely no warranty.
128 *
129 * This differs from Colin Plumb's older public domain implementation in
130 * that no 32-bit integer data type is required, there's no compile-time
131 * endianness configuration, and the function prototypes match OpenSSL's.
132 * The primary goals are portability and ease of use.
133 *
134 * This implementation is meant to be fast, but not as fast as possible.
135 * Some known optimizations are not included to reduce source code size
136 * and avoid compile-time configuration.
137 */
138
139 #include <string.h>
140
141 /*
142 * The basic MD5 functions.
143 *
144 * F and G are optimized compared to their RFC 1321 definitions for
145 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
146 * implementation.
147 */
148 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
149 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
150 #define H(x, y, z) ((x) ^ (y) ^ (z))
151 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
152
153 /*
154 * The MD5 transformation for all four rounds.
155 */
156 #define STEP(f, a, b, c, d, x, t, s) \
157 (a) += f((b), (c), (d)) + (x) + (t); \
158 (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
159 (a) += (b);
160
161 /*
162 * SET reads 4 input bytes in little-endian byte order and stores them
163 * in a properly aligned word in host byte order.
164 *
165 * The check for little-endian architectures that tolerate unaligned
166 * memory accesses is just an optimization. Nothing will break if it
167 * doesn't work.
168 */
169 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
170 # define SET(n) \
171 (*(uint32_t *)&ptr[(n) * 4])
172 # define GET(n) \
173 SET(n)
174 #else
175 # define SET(n) \
176 (ctx->block[(n)] = \
177 (uint32_t)ptr[(n) * 4] | \
178 ((uint32_t)ptr[(n) * 4 + 1] << 8) | \
179 ((uint32_t)ptr[(n) * 4 + 2] << 16) | \
180 ((uint32_t)ptr[(n) * 4 + 3] << 24))
181 # define GET(n) \
182 (ctx->block[(n)])
183 #endif
184
185 /*
186 * This processes one or more 64-byte data blocks, but does NOT update
187 * the bit counters. There are no alignment requirements.
188 */
body(PHP_MD5_CTX * ctx,const void * data,size_t size)189 static const void *body(PHP_MD5_CTX *ctx, const void *data, size_t size)
190 {
191 const unsigned char *ptr;
192 uint32_t a, b, c, d;
193 uint32_t saved_a, saved_b, saved_c, saved_d;
194
195 ptr = data;
196
197 a = ctx->a;
198 b = ctx->b;
199 c = ctx->c;
200 d = ctx->d;
201
202 do {
203 saved_a = a;
204 saved_b = b;
205 saved_c = c;
206 saved_d = d;
207
208 /* Round 1 */
209 STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
210 STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
211 STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
212 STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
213 STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
214 STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
215 STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
216 STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
217 STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
218 STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
219 STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
220 STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
221 STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
222 STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
223 STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
224 STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
225
226 /* Round 2 */
227 STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
228 STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
229 STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
230 STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
231 STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
232 STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
233 STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
234 STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
235 STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
236 STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
237 STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
238 STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
239 STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
240 STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
241 STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
242 STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
243
244 /* Round 3 */
245 STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
246 STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
247 STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
248 STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
249 STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
250 STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
251 STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
252 STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
253 STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
254 STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
255 STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
256 STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
257 STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
258 STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
259 STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
260 STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
261
262 /* Round 4 */
263 STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
264 STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
265 STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
266 STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
267 STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
268 STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
269 STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
270 STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
271 STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
272 STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
273 STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
274 STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
275 STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
276 STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
277 STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
278 STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
279
280 a += saved_a;
281 b += saved_b;
282 c += saved_c;
283 d += saved_d;
284
285 ptr += 64;
286 } while (size -= 64);
287
288 ctx->a = a;
289 ctx->b = b;
290 ctx->c = c;
291 ctx->d = d;
292
293 return ptr;
294 }
295
PHP_MD5Init(PHP_MD5_CTX * ctx)296 PHPAPI void PHP_MD5Init(PHP_MD5_CTX *ctx)
297 {
298 ctx->a = 0x67452301;
299 ctx->b = 0xefcdab89;
300 ctx->c = 0x98badcfe;
301 ctx->d = 0x10325476;
302
303 ctx->lo = 0;
304 ctx->hi = 0;
305 }
306
PHP_MD5Update(PHP_MD5_CTX * ctx,const void * data,size_t size)307 PHPAPI void PHP_MD5Update(PHP_MD5_CTX *ctx, const void *data, size_t size)
308 {
309 uint32_t saved_lo;
310 uint32_t used, free;
311
312 saved_lo = ctx->lo;
313 if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) {
314 ctx->hi++;
315 }
316 ctx->hi += size >> 29;
317
318 used = saved_lo & 0x3f;
319
320 if (used) {
321 free = 64 - used;
322
323 if (size < free) {
324 memcpy(&ctx->buffer[used], data, size);
325 return;
326 }
327
328 memcpy(&ctx->buffer[used], data, free);
329 data = (unsigned char *)data + free;
330 size -= free;
331 body(ctx, ctx->buffer, 64);
332 }
333
334 if (size >= 64) {
335 data = body(ctx, data, size & ~(size_t)0x3f);
336 size &= 0x3f;
337 }
338
339 memcpy(ctx->buffer, data, size);
340 }
341
PHP_MD5Final(unsigned char * result,PHP_MD5_CTX * ctx)342 PHPAPI void PHP_MD5Final(unsigned char *result, PHP_MD5_CTX *ctx)
343 {
344 uint32_t used, free;
345
346 used = ctx->lo & 0x3f;
347
348 ctx->buffer[used++] = 0x80;
349
350 free = 64 - used;
351
352 if (free < 8) {
353 memset(&ctx->buffer[used], 0, free);
354 body(ctx, ctx->buffer, 64);
355 used = 0;
356 free = 64;
357 }
358
359 memset(&ctx->buffer[used], 0, free - 8);
360
361 ctx->lo <<= 3;
362 ctx->buffer[56] = ctx->lo;
363 ctx->buffer[57] = ctx->lo >> 8;
364 ctx->buffer[58] = ctx->lo >> 16;
365 ctx->buffer[59] = ctx->lo >> 24;
366 ctx->buffer[60] = ctx->hi;
367 ctx->buffer[61] = ctx->hi >> 8;
368 ctx->buffer[62] = ctx->hi >> 16;
369 ctx->buffer[63] = ctx->hi >> 24;
370
371 body(ctx, ctx->buffer, 64);
372
373 result[0] = ctx->a;
374 result[1] = ctx->a >> 8;
375 result[2] = ctx->a >> 16;
376 result[3] = ctx->a >> 24;
377 result[4] = ctx->b;
378 result[5] = ctx->b >> 8;
379 result[6] = ctx->b >> 16;
380 result[7] = ctx->b >> 24;
381 result[8] = ctx->c;
382 result[9] = ctx->c >> 8;
383 result[10] = ctx->c >> 16;
384 result[11] = ctx->c >> 24;
385 result[12] = ctx->d;
386 result[13] = ctx->d >> 8;
387 result[14] = ctx->d >> 16;
388 result[15] = ctx->d >> 24;
389
390 ZEND_SECURE_ZERO(ctx, sizeof(*ctx));
391 }
392
393 /*
394 * Local variables:
395 * tab-width: 4
396 * c-basic-offset: 4
397 * End:
398 * vim600: sw=4 ts=4 fdm=marker
399 * vim<600: sw=4 ts=4
400 */
401