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 | http://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 zend_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 zend_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_MD5Init(PHP_MD5_CTX * ctx)293 PHPAPI void PHP_MD5Init(PHP_MD5_CTX *ctx)
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