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