1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 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