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