root/ext/hash/hash_whirlpool.c

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

DEFINITIONS

This source file includes following definitions.
  1. WhirlpoolTransform
  2. PHP_WHIRLPOOLInit
  3. PHP_WHIRLPOOLUpdate
  4. PHP_WHIRLPOOLFinal

   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   | Authors: Michael Wallner <mike@php.net>                              |
  16   |          Sara Golemon <pollita@php.net>                              |
  17   +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id$ */
  21 
  22 #include "php_hash.h"
  23 
  24 /*
  25  * TODO: simplify Update and Final, those look ridiculously complex
  26  * Mike, 2005-11-23
  27  */
  28 
  29 #include "php_hash_whirlpool.h"
  30 #include "php_hash_whirlpool_tables.h"
  31 
  32 #define DIGESTBYTES 64
  33 #define DIGESTBITS  (8*DIGESTBYTES) /* 512 */
  34 
  35 #define WBLOCKBYTES 64
  36 #define WBLOCKBITS  (8*WBLOCKBYTES) /* 512 */
  37 
  38 #define LENGTHBYTES 32
  39 #define LENGTHBITS  (8*LENGTHBYTES) /* 256 */
  40 
  41 static void WhirlpoolTransform(PHP_WHIRLPOOL_CTX *context)
  42 {
  43     int i, r;
  44     php_hash_uint64 K[8];        /* the round key */
  45     php_hash_uint64 block[8];    /* mu(buffer) */
  46     php_hash_uint64 state[8];    /* the cipher state */
  47     php_hash_uint64 L[8];
  48     unsigned char *buffer = context->buffer.data;
  49 
  50     /*
  51      * map the buffer to a block:
  52      */
  53     for (i = 0; i < 8; i++, buffer += 8) {
  54         block[i] =
  55             (((php_hash_uint64)buffer[0]        ) << 56) ^
  56             (((php_hash_uint64)buffer[1] & 0xffL) << 48) ^
  57             (((php_hash_uint64)buffer[2] & 0xffL) << 40) ^
  58             (((php_hash_uint64)buffer[3] & 0xffL) << 32) ^
  59             (((php_hash_uint64)buffer[4] & 0xffL) << 24) ^
  60             (((php_hash_uint64)buffer[5] & 0xffL) << 16) ^
  61             (((php_hash_uint64)buffer[6] & 0xffL) <<  8) ^
  62             (((php_hash_uint64)buffer[7] & 0xffL)      );
  63     }
  64     /*
  65      * compute and apply K^0 to the cipher state:
  66      */
  67     state[0] = block[0] ^ (K[0] = context->state[0]);
  68     state[1] = block[1] ^ (K[1] = context->state[1]);
  69     state[2] = block[2] ^ (K[2] = context->state[2]);
  70     state[3] = block[3] ^ (K[3] = context->state[3]);
  71     state[4] = block[4] ^ (K[4] = context->state[4]);
  72     state[5] = block[5] ^ (K[5] = context->state[5]);
  73     state[6] = block[6] ^ (K[6] = context->state[6]);
  74     state[7] = block[7] ^ (K[7] = context->state[7]);
  75     /*
  76      * iterate over all rounds:
  77      */
  78     for (r = 1; r <= R; r++) {
  79         /*
  80          * compute K^r from K^{r-1}:
  81          */
  82         L[0] =
  83             C0[(int)(K[0] >> 56)       ] ^
  84             C1[(int)(K[7] >> 48) & 0xff] ^
  85             C2[(int)(K[6] >> 40) & 0xff] ^
  86             C3[(int)(K[5] >> 32) & 0xff] ^
  87             C4[(int)(K[4] >> 24) & 0xff] ^
  88             C5[(int)(K[3] >> 16) & 0xff] ^
  89             C6[(int)(K[2] >>  8) & 0xff] ^
  90             C7[(int)(K[1]      ) & 0xff] ^
  91             rc[r];
  92         L[1] =
  93             C0[(int)(K[1] >> 56)       ] ^
  94             C1[(int)(K[0] >> 48) & 0xff] ^
  95             C2[(int)(K[7] >> 40) & 0xff] ^
  96             C3[(int)(K[6] >> 32) & 0xff] ^
  97             C4[(int)(K[5] >> 24) & 0xff] ^
  98             C5[(int)(K[4] >> 16) & 0xff] ^
  99             C6[(int)(K[3] >>  8) & 0xff] ^
 100             C7[(int)(K[2]      ) & 0xff];
 101         L[2] =
 102             C0[(int)(K[2] >> 56)       ] ^
 103             C1[(int)(K[1] >> 48) & 0xff] ^
 104             C2[(int)(K[0] >> 40) & 0xff] ^
 105             C3[(int)(K[7] >> 32) & 0xff] ^
 106             C4[(int)(K[6] >> 24) & 0xff] ^
 107             C5[(int)(K[5] >> 16) & 0xff] ^
 108             C6[(int)(K[4] >>  8) & 0xff] ^
 109             C7[(int)(K[3]      ) & 0xff];
 110         L[3] =
 111             C0[(int)(K[3] >> 56)       ] ^
 112             C1[(int)(K[2] >> 48) & 0xff] ^
 113             C2[(int)(K[1] >> 40) & 0xff] ^
 114             C3[(int)(K[0] >> 32) & 0xff] ^
 115             C4[(int)(K[7] >> 24) & 0xff] ^
 116             C5[(int)(K[6] >> 16) & 0xff] ^
 117             C6[(int)(K[5] >>  8) & 0xff] ^
 118             C7[(int)(K[4]      ) & 0xff];
 119         L[4] =
 120             C0[(int)(K[4] >> 56)       ] ^
 121             C1[(int)(K[3] >> 48) & 0xff] ^
 122             C2[(int)(K[2] >> 40) & 0xff] ^
 123             C3[(int)(K[1] >> 32) & 0xff] ^
 124             C4[(int)(K[0] >> 24) & 0xff] ^
 125             C5[(int)(K[7] >> 16) & 0xff] ^
 126             C6[(int)(K[6] >>  8) & 0xff] ^
 127             C7[(int)(K[5]      ) & 0xff];
 128         L[5] =
 129             C0[(int)(K[5] >> 56)       ] ^
 130             C1[(int)(K[4] >> 48) & 0xff] ^
 131             C2[(int)(K[3] >> 40) & 0xff] ^
 132             C3[(int)(K[2] >> 32) & 0xff] ^
 133             C4[(int)(K[1] >> 24) & 0xff] ^
 134             C5[(int)(K[0] >> 16) & 0xff] ^
 135             C6[(int)(K[7] >>  8) & 0xff] ^
 136             C7[(int)(K[6]      ) & 0xff];
 137         L[6] =
 138             C0[(int)(K[6] >> 56)       ] ^
 139             C1[(int)(K[5] >> 48) & 0xff] ^
 140             C2[(int)(K[4] >> 40) & 0xff] ^
 141             C3[(int)(K[3] >> 32) & 0xff] ^
 142             C4[(int)(K[2] >> 24) & 0xff] ^
 143             C5[(int)(K[1] >> 16) & 0xff] ^
 144             C6[(int)(K[0] >>  8) & 0xff] ^
 145             C7[(int)(K[7]      ) & 0xff];
 146         L[7] =
 147             C0[(int)(K[7] >> 56)       ] ^
 148             C1[(int)(K[6] >> 48) & 0xff] ^
 149             C2[(int)(K[5] >> 40) & 0xff] ^
 150             C3[(int)(K[4] >> 32) & 0xff] ^
 151             C4[(int)(K[3] >> 24) & 0xff] ^
 152             C5[(int)(K[2] >> 16) & 0xff] ^
 153             C6[(int)(K[1] >>  8) & 0xff] ^
 154             C7[(int)(K[0]      ) & 0xff];
 155         K[0] = L[0];
 156         K[1] = L[1];
 157         K[2] = L[2];
 158         K[3] = L[3];
 159         K[4] = L[4];
 160         K[5] = L[5];
 161         K[6] = L[6];
 162         K[7] = L[7];
 163         /*
 164          * apply the r-th round transformation:
 165          */
 166         L[0] =
 167             C0[(int)(state[0] >> 56)       ] ^
 168             C1[(int)(state[7] >> 48) & 0xff] ^
 169             C2[(int)(state[6] >> 40) & 0xff] ^
 170             C3[(int)(state[5] >> 32) & 0xff] ^
 171             C4[(int)(state[4] >> 24) & 0xff] ^
 172             C5[(int)(state[3] >> 16) & 0xff] ^
 173             C6[(int)(state[2] >>  8) & 0xff] ^
 174             C7[(int)(state[1]      ) & 0xff] ^
 175             K[0];
 176         L[1] =
 177             C0[(int)(state[1] >> 56)       ] ^
 178             C1[(int)(state[0] >> 48) & 0xff] ^
 179             C2[(int)(state[7] >> 40) & 0xff] ^
 180             C3[(int)(state[6] >> 32) & 0xff] ^
 181             C4[(int)(state[5] >> 24) & 0xff] ^
 182             C5[(int)(state[4] >> 16) & 0xff] ^
 183             C6[(int)(state[3] >>  8) & 0xff] ^
 184             C7[(int)(state[2]      ) & 0xff] ^
 185             K[1];
 186         L[2] =
 187             C0[(int)(state[2] >> 56)       ] ^
 188             C1[(int)(state[1] >> 48) & 0xff] ^
 189             C2[(int)(state[0] >> 40) & 0xff] ^
 190             C3[(int)(state[7] >> 32) & 0xff] ^
 191             C4[(int)(state[6] >> 24) & 0xff] ^
 192             C5[(int)(state[5] >> 16) & 0xff] ^
 193             C6[(int)(state[4] >>  8) & 0xff] ^
 194             C7[(int)(state[3]      ) & 0xff] ^
 195             K[2];
 196         L[3] =
 197             C0[(int)(state[3] >> 56)       ] ^
 198             C1[(int)(state[2] >> 48) & 0xff] ^
 199             C2[(int)(state[1] >> 40) & 0xff] ^
 200             C3[(int)(state[0] >> 32) & 0xff] ^
 201             C4[(int)(state[7] >> 24) & 0xff] ^
 202             C5[(int)(state[6] >> 16) & 0xff] ^
 203             C6[(int)(state[5] >>  8) & 0xff] ^
 204             C7[(int)(state[4]      ) & 0xff] ^
 205             K[3];
 206         L[4] =
 207             C0[(int)(state[4] >> 56)       ] ^
 208             C1[(int)(state[3] >> 48) & 0xff] ^
 209             C2[(int)(state[2] >> 40) & 0xff] ^
 210             C3[(int)(state[1] >> 32) & 0xff] ^
 211             C4[(int)(state[0] >> 24) & 0xff] ^
 212             C5[(int)(state[7] >> 16) & 0xff] ^
 213             C6[(int)(state[6] >>  8) & 0xff] ^
 214             C7[(int)(state[5]      ) & 0xff] ^
 215             K[4];
 216         L[5] =
 217             C0[(int)(state[5] >> 56)       ] ^
 218             C1[(int)(state[4] >> 48) & 0xff] ^
 219             C2[(int)(state[3] >> 40) & 0xff] ^
 220             C3[(int)(state[2] >> 32) & 0xff] ^
 221             C4[(int)(state[1] >> 24) & 0xff] ^
 222             C5[(int)(state[0] >> 16) & 0xff] ^
 223             C6[(int)(state[7] >>  8) & 0xff] ^
 224             C7[(int)(state[6]      ) & 0xff] ^
 225             K[5];
 226         L[6] =
 227             C0[(int)(state[6] >> 56)       ] ^
 228             C1[(int)(state[5] >> 48) & 0xff] ^
 229             C2[(int)(state[4] >> 40) & 0xff] ^
 230             C3[(int)(state[3] >> 32) & 0xff] ^
 231             C4[(int)(state[2] >> 24) & 0xff] ^
 232             C5[(int)(state[1] >> 16) & 0xff] ^
 233             C6[(int)(state[0] >>  8) & 0xff] ^
 234             C7[(int)(state[7]      ) & 0xff] ^
 235             K[6];
 236         L[7] =
 237             C0[(int)(state[7] >> 56)       ] ^
 238             C1[(int)(state[6] >> 48) & 0xff] ^
 239             C2[(int)(state[5] >> 40) & 0xff] ^
 240             C3[(int)(state[4] >> 32) & 0xff] ^
 241             C4[(int)(state[3] >> 24) & 0xff] ^
 242             C5[(int)(state[2] >> 16) & 0xff] ^
 243             C6[(int)(state[1] >>  8) & 0xff] ^
 244             C7[(int)(state[0]      ) & 0xff] ^
 245             K[7];
 246         state[0] = L[0];
 247         state[1] = L[1];
 248         state[2] = L[2];
 249         state[3] = L[3];
 250         state[4] = L[4];
 251         state[5] = L[5];
 252         state[6] = L[6];
 253         state[7] = L[7];
 254     }
 255     /*
 256      * apply the Miyaguchi-Preneel compression function:
 257      */
 258     context->state[0] ^= state[0] ^ block[0];
 259     context->state[1] ^= state[1] ^ block[1];
 260     context->state[2] ^= state[2] ^ block[2];
 261     context->state[3] ^= state[3] ^ block[3];
 262     context->state[4] ^= state[4] ^ block[4];
 263     context->state[5] ^= state[5] ^ block[5];
 264     context->state[6] ^= state[6] ^ block[6];
 265     context->state[7] ^= state[7] ^ block[7];
 266 
 267         ZEND_SECURE_ZERO(state, sizeof(state));
 268 }
 269 
 270 PHP_HASH_API void PHP_WHIRLPOOLInit(PHP_WHIRLPOOL_CTX *context)
 271 {
 272         memset(context, 0, sizeof(*context));
 273 }
 274 
 275 PHP_HASH_API void PHP_WHIRLPOOLUpdate(PHP_WHIRLPOOL_CTX *context, const unsigned char *input, size_t len)
 276 {
 277     php_hash_uint64 sourceBits = len * 8;
 278     int sourcePos    = 0; /* index of leftmost source unsigned char containing data (1 to 8 bits). */
 279     int sourceGap    = (8 - ((int)sourceBits & 7)) & 7; /* space on source[sourcePos]. */
 280     int bufferRem    = context->buffer.bits & 7; /* occupied bits on buffer[bufferPos]. */
 281     const unsigned char *source = input;
 282     unsigned char *buffer       = context->buffer.data;
 283     unsigned char *bitLength    = context->bitlength;
 284     int bufferBits   = context->buffer.bits;
 285     int bufferPos    = context->buffer.pos;
 286     php_hash_uint32 b, carry;
 287     int i;
 288 
 289     /*
 290      * tally the length of the added data:
 291      */
 292     php_hash_uint64 value = sourceBits;
 293     for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != L64(0)); i--) {
 294         carry += bitLength[i] + ((php_hash_uint32)value & 0xff);
 295         bitLength[i] = (unsigned char)carry;
 296         carry >>= 8;
 297         value >>= 8;
 298     }
 299     /*
 300      * process data in chunks of 8 bits (a more efficient approach would be to take whole-word chunks):
 301      */
 302     while (sourceBits > 8) {
 303         /* N.B. at least source[sourcePos] and source[sourcePos+1] contain data. */
 304         /*
 305          * take a byte from the source:
 306          */
 307         b = ((source[sourcePos] << sourceGap) & 0xff) |
 308             ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
 309         /*
 310          * process this byte:
 311          */
 312         buffer[bufferPos++] |= (unsigned char)(b >> bufferRem);
 313         bufferBits += 8 - bufferRem; /* bufferBits = 8*bufferPos; */
 314         if (bufferBits == DIGESTBITS) {
 315             /*
 316              * process data block:
 317              */
 318             WhirlpoolTransform(context);
 319             /*
 320              * reset buffer:
 321              */
 322             bufferBits = bufferPos = 0;
 323         }
 324         buffer[bufferPos] = (unsigned char) (b << (8 - bufferRem));
 325         bufferBits += bufferRem;
 326         /*
 327          * proceed to remaining data:
 328          */
 329         sourceBits -= 8;
 330         sourcePos++;
 331     }
 332     /* now 0 <= sourceBits <= 8;
 333      * furthermore, all data (if any is left) is in source[sourcePos].
 334      */
 335     if (sourceBits > 0) {
 336         b = (source[sourcePos] << sourceGap) & 0xff; /* bits are left-justified on b. */
 337         /*
 338          * process the remaining bits:
 339          */
 340         buffer[bufferPos] |= b >> bufferRem;
 341     } else {
 342         b = 0;
 343     }
 344     if (bufferRem + sourceBits < 8) {
 345         /*
 346          * all remaining data fits on buffer[bufferPos],
 347          * and there still remains some space.
 348          */
 349         bufferBits += (int) sourceBits;
 350     } else {
 351         /*
 352          * buffer[bufferPos] is full:
 353          */
 354         bufferPos++;
 355         bufferBits += 8 - bufferRem; /* bufferBits = 8*bufferPos; */
 356         sourceBits -= 8 - bufferRem;
 357         /* now 0 <= sourceBits < 8;
 358          * furthermore, all data (if any is left) is in source[sourcePos].
 359          */
 360         if (bufferBits == DIGESTBITS) {
 361             /*
 362              * process data block:
 363              */
 364             WhirlpoolTransform(context);
 365             /*
 366              * reset buffer:
 367              */
 368             bufferBits = bufferPos = 0;
 369         }
 370         buffer[bufferPos] = (unsigned char) (b << (8 - bufferRem));
 371         bufferBits += (int)sourceBits;
 372     }
 373     context->buffer.bits   = bufferBits;
 374     context->buffer.pos    = bufferPos;
 375 }
 376 
 377 PHP_HASH_API void PHP_WHIRLPOOLFinal(unsigned char digest[64], PHP_WHIRLPOOL_CTX *context)
 378 {
 379     int i;
 380     unsigned char *buffer      = context->buffer.data;
 381     unsigned char *bitLength   = context->bitlength;
 382     int bufferBits  = context->buffer.bits;
 383     int bufferPos   = context->buffer.pos;
 384 
 385     /*
 386      * append a '1'-bit:
 387      */
 388     buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
 389     bufferPos++; /* all remaining bits on the current unsigned char are set to zero. */
 390     /*
 391      * pad with zero bits to complete (N*WBLOCKBITS - LENGTHBITS) bits:
 392      */
 393     if (bufferPos > WBLOCKBYTES - LENGTHBYTES) {
 394         if (bufferPos < WBLOCKBYTES) {
 395             memset(&buffer[bufferPos], 0, WBLOCKBYTES - bufferPos);
 396         }
 397         /*
 398          * process data block:
 399          */
 400         WhirlpoolTransform(context);
 401         /*
 402          * reset buffer:
 403          */
 404         bufferPos = 0;
 405     }
 406     if (bufferPos < WBLOCKBYTES - LENGTHBYTES) {
 407         memset(&buffer[bufferPos], 0, (WBLOCKBYTES - LENGTHBYTES) - bufferPos);
 408     }
 409     bufferPos = WBLOCKBYTES - LENGTHBYTES;
 410     /*
 411      * append bit length of hashed data:
 412      */
 413     memcpy(&buffer[WBLOCKBYTES - LENGTHBYTES], bitLength, LENGTHBYTES);
 414     /*
 415      * process data block:
 416      */
 417     WhirlpoolTransform(context);
 418     /*
 419      * return the completed message digest:
 420      */
 421     for (i = 0; i < DIGESTBYTES/8; i++) {
 422         digest[0] = (unsigned char)(context->state[i] >> 56);
 423         digest[1] = (unsigned char)(context->state[i] >> 48);
 424         digest[2] = (unsigned char)(context->state[i] >> 40);
 425         digest[3] = (unsigned char)(context->state[i] >> 32);
 426         digest[4] = (unsigned char)(context->state[i] >> 24);
 427         digest[5] = (unsigned char)(context->state[i] >> 16);
 428         digest[6] = (unsigned char)(context->state[i] >>  8);
 429         digest[7] = (unsigned char)(context->state[i]      );
 430         digest += 8;
 431     }
 432 
 433     ZEND_SECURE_ZERO(context, sizeof(*context));
 434 }
 435 
 436 const php_hash_ops php_hash_whirlpool_ops = {
 437         (php_hash_init_func_t) PHP_WHIRLPOOLInit,
 438         (php_hash_update_func_t) PHP_WHIRLPOOLUpdate,
 439         (php_hash_final_func_t) PHP_WHIRLPOOLFinal,
 440         (php_hash_copy_func_t) php_hash_copy,
 441         64,
 442         64,
 443         sizeof(PHP_WHIRLPOOL_CTX)
 444 };
 445 
 446 /*
 447  * Local variables:
 448  * tab-width: 4
 449  * c-basic-offset: 4
 450  * End:
 451  * vim600: sw=4 ts=4 fdm=marker
 452  * vim<600: sw=4 ts=4
 453  */

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