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 5                                                        |
   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         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 */
  76 PHP_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  */
 187 static 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 
 294 PHPAPI 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 
 305 PHPAPI 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 
 340 PHPAPI 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 }

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