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