xref: /PHP-7.3/ext/standard/md5.c (revision 8d3f8ca1)
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