1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 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, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { 89 return; 90 } 91 92 stream = php_stream_open_wrapper(arg, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, 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