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