root/ext/standard/md5.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. make_digest
  2. make_digest_ex
  3. PHP_NAMED_FUNCTION
  4. PHP_NAMED_FUNCTION
  5. body
  6. PHP_MD5Init
  7. PHP_MD5Update
  8. PHP_MD5Final

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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 
  26 PHPAPI void make_digest(char *md5str, const unsigned char *digest) /* {{{ */
  27 {
  28         make_digest_ex(md5str, digest, 16);
  29 }
  30 /* }}} */
  31 
  32 PHPAPI 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 */
  47 PHP_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, ZSTR_VAL(arg), ZSTR_LEN(arg));
  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 */
  75 PHP_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  */
 190 static 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 
 297 PHPAPI 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 
 308 PHPAPI 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 
 343 PHPAPI 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 }

/* [<][>][^][v][top][bottom][index][help] */