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