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