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 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 */
PHP_NAMED_FUNCTION(php_if_md5_file)75 PHP_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 */
body(PHP_MD5_CTX * ctx,const void * data,size_t size)190 static 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
PHP_MD5Init(PHP_MD5_CTX * ctx)297 PHPAPI 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
PHP_MD5Update(PHP_MD5_CTX * ctx,const void * data,size_t size)308 PHPAPI 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
PHP_MD5Final(unsigned char * result,PHP_MD5_CTX * ctx)343 PHPAPI 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