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