Back to index

php5  5.3.10
hash_whirlpool.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Michael Wallner <mike@php.net>                              |
00016   |          Sara Golemon <pollita@php.net>                              |
00017   +----------------------------------------------------------------------+
00018 */
00019 
00020 /* $Id: hash_whirlpool.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php_hash.h"
00023 
00024 /*
00025  * TODO: simplify Update and Final, those look ridiculously complex
00026  * Mike, 2005-11-23 
00027  */
00028 
00029 #include "php_hash_whirlpool.h"
00030 #include "php_hash_whirlpool_tables.h"
00031 
00032 #define DIGESTBYTES 64
00033 #define DIGESTBITS  (8*DIGESTBYTES) /* 512 */
00034 
00035 #define WBLOCKBYTES 64
00036 #define WBLOCKBITS  (8*WBLOCKBYTES) /* 512 */
00037 
00038 #define LENGTHBYTES 32
00039 #define LENGTHBITS  (8*LENGTHBYTES) /* 256 */
00040 
00041 static void WhirlpoolTransform(PHP_WHIRLPOOL_CTX *context)
00042 {
00043     int i, r;
00044     php_hash_uint64 K[8];        /* the round key */
00045     php_hash_uint64 block[8];    /* mu(buffer) */
00046     php_hash_uint64 state[8];    /* the cipher state */
00047     php_hash_uint64 L[8];
00048     unsigned char *buffer = context->buffer.data;
00049 
00050     /*
00051      * map the buffer to a block:
00052      */
00053     for (i = 0; i < 8; i++, buffer += 8) {
00054         block[i] =
00055             (((php_hash_uint64)buffer[0]        ) << 56) ^
00056             (((php_hash_uint64)buffer[1] & 0xffL) << 48) ^
00057             (((php_hash_uint64)buffer[2] & 0xffL) << 40) ^
00058             (((php_hash_uint64)buffer[3] & 0xffL) << 32) ^
00059             (((php_hash_uint64)buffer[4] & 0xffL) << 24) ^
00060             (((php_hash_uint64)buffer[5] & 0xffL) << 16) ^
00061             (((php_hash_uint64)buffer[6] & 0xffL) <<  8) ^
00062             (((php_hash_uint64)buffer[7] & 0xffL)      );
00063     }
00064     /*
00065      * compute and apply K^0 to the cipher state:
00066      */
00067     state[0] = block[0] ^ (K[0] = context->state[0]);
00068     state[1] = block[1] ^ (K[1] = context->state[1]);
00069     state[2] = block[2] ^ (K[2] = context->state[2]);
00070     state[3] = block[3] ^ (K[3] = context->state[3]);
00071     state[4] = block[4] ^ (K[4] = context->state[4]);
00072     state[5] = block[5] ^ (K[5] = context->state[5]);
00073     state[6] = block[6] ^ (K[6] = context->state[6]);
00074     state[7] = block[7] ^ (K[7] = context->state[7]);
00075     /*
00076      * iterate over all rounds:
00077      */
00078     for (r = 1; r <= R; r++) {
00079         /*
00080          * compute K^r from K^{r-1}:
00081          */
00082         L[0] =
00083             C0[(int)(K[0] >> 56)       ] ^
00084             C1[(int)(K[7] >> 48) & 0xff] ^
00085             C2[(int)(K[6] >> 40) & 0xff] ^
00086             C3[(int)(K[5] >> 32) & 0xff] ^
00087             C4[(int)(K[4] >> 24) & 0xff] ^
00088             C5[(int)(K[3] >> 16) & 0xff] ^
00089             C6[(int)(K[2] >>  8) & 0xff] ^
00090             C7[(int)(K[1]      ) & 0xff] ^
00091             rc[r];
00092         L[1] =
00093             C0[(int)(K[1] >> 56)       ] ^
00094             C1[(int)(K[0] >> 48) & 0xff] ^
00095             C2[(int)(K[7] >> 40) & 0xff] ^
00096             C3[(int)(K[6] >> 32) & 0xff] ^
00097             C4[(int)(K[5] >> 24) & 0xff] ^
00098             C5[(int)(K[4] >> 16) & 0xff] ^
00099             C6[(int)(K[3] >>  8) & 0xff] ^
00100             C7[(int)(K[2]      ) & 0xff];
00101         L[2] =
00102             C0[(int)(K[2] >> 56)       ] ^
00103             C1[(int)(K[1] >> 48) & 0xff] ^
00104             C2[(int)(K[0] >> 40) & 0xff] ^
00105             C3[(int)(K[7] >> 32) & 0xff] ^
00106             C4[(int)(K[6] >> 24) & 0xff] ^
00107             C5[(int)(K[5] >> 16) & 0xff] ^
00108             C6[(int)(K[4] >>  8) & 0xff] ^
00109             C7[(int)(K[3]      ) & 0xff];
00110         L[3] =
00111             C0[(int)(K[3] >> 56)       ] ^
00112             C1[(int)(K[2] >> 48) & 0xff] ^
00113             C2[(int)(K[1] >> 40) & 0xff] ^
00114             C3[(int)(K[0] >> 32) & 0xff] ^
00115             C4[(int)(K[7] >> 24) & 0xff] ^
00116             C5[(int)(K[6] >> 16) & 0xff] ^
00117             C6[(int)(K[5] >>  8) & 0xff] ^
00118             C7[(int)(K[4]      ) & 0xff];
00119         L[4] =
00120             C0[(int)(K[4] >> 56)       ] ^
00121             C1[(int)(K[3] >> 48) & 0xff] ^
00122             C2[(int)(K[2] >> 40) & 0xff] ^
00123             C3[(int)(K[1] >> 32) & 0xff] ^
00124             C4[(int)(K[0] >> 24) & 0xff] ^
00125             C5[(int)(K[7] >> 16) & 0xff] ^
00126             C6[(int)(K[6] >>  8) & 0xff] ^
00127             C7[(int)(K[5]      ) & 0xff];
00128         L[5] =
00129             C0[(int)(K[5] >> 56)       ] ^
00130             C1[(int)(K[4] >> 48) & 0xff] ^
00131             C2[(int)(K[3] >> 40) & 0xff] ^
00132             C3[(int)(K[2] >> 32) & 0xff] ^
00133             C4[(int)(K[1] >> 24) & 0xff] ^
00134             C5[(int)(K[0] >> 16) & 0xff] ^
00135             C6[(int)(K[7] >>  8) & 0xff] ^
00136             C7[(int)(K[6]      ) & 0xff];
00137         L[6] =
00138             C0[(int)(K[6] >> 56)       ] ^
00139             C1[(int)(K[5] >> 48) & 0xff] ^
00140             C2[(int)(K[4] >> 40) & 0xff] ^
00141             C3[(int)(K[3] >> 32) & 0xff] ^
00142             C4[(int)(K[2] >> 24) & 0xff] ^
00143             C5[(int)(K[1] >> 16) & 0xff] ^
00144             C6[(int)(K[0] >>  8) & 0xff] ^
00145             C7[(int)(K[7]      ) & 0xff];
00146         L[7] =
00147             C0[(int)(K[7] >> 56)       ] ^
00148             C1[(int)(K[6] >> 48) & 0xff] ^
00149             C2[(int)(K[5] >> 40) & 0xff] ^
00150             C3[(int)(K[4] >> 32) & 0xff] ^
00151             C4[(int)(K[3] >> 24) & 0xff] ^
00152             C5[(int)(K[2] >> 16) & 0xff] ^
00153             C6[(int)(K[1] >>  8) & 0xff] ^
00154             C7[(int)(K[0]      ) & 0xff];
00155         K[0] = L[0];
00156         K[1] = L[1];
00157         K[2] = L[2];
00158         K[3] = L[3];
00159         K[4] = L[4];
00160         K[5] = L[5];
00161         K[6] = L[6];
00162         K[7] = L[7];
00163         /*
00164          * apply the r-th round transformation:
00165          */
00166         L[0] =
00167             C0[(int)(state[0] >> 56)       ] ^
00168             C1[(int)(state[7] >> 48) & 0xff] ^
00169             C2[(int)(state[6] >> 40) & 0xff] ^
00170             C3[(int)(state[5] >> 32) & 0xff] ^
00171             C4[(int)(state[4] >> 24) & 0xff] ^
00172             C5[(int)(state[3] >> 16) & 0xff] ^
00173             C6[(int)(state[2] >>  8) & 0xff] ^
00174             C7[(int)(state[1]      ) & 0xff] ^
00175             K[0];
00176         L[1] =
00177             C0[(int)(state[1] >> 56)       ] ^
00178             C1[(int)(state[0] >> 48) & 0xff] ^
00179             C2[(int)(state[7] >> 40) & 0xff] ^
00180             C3[(int)(state[6] >> 32) & 0xff] ^
00181             C4[(int)(state[5] >> 24) & 0xff] ^
00182             C5[(int)(state[4] >> 16) & 0xff] ^
00183             C6[(int)(state[3] >>  8) & 0xff] ^
00184             C7[(int)(state[2]      ) & 0xff] ^
00185             K[1];
00186         L[2] =
00187             C0[(int)(state[2] >> 56)       ] ^
00188             C1[(int)(state[1] >> 48) & 0xff] ^
00189             C2[(int)(state[0] >> 40) & 0xff] ^
00190             C3[(int)(state[7] >> 32) & 0xff] ^
00191             C4[(int)(state[6] >> 24) & 0xff] ^
00192             C5[(int)(state[5] >> 16) & 0xff] ^
00193             C6[(int)(state[4] >>  8) & 0xff] ^
00194             C7[(int)(state[3]      ) & 0xff] ^
00195             K[2];
00196         L[3] =
00197             C0[(int)(state[3] >> 56)       ] ^
00198             C1[(int)(state[2] >> 48) & 0xff] ^
00199             C2[(int)(state[1] >> 40) & 0xff] ^
00200             C3[(int)(state[0] >> 32) & 0xff] ^
00201             C4[(int)(state[7] >> 24) & 0xff] ^
00202             C5[(int)(state[6] >> 16) & 0xff] ^
00203             C6[(int)(state[5] >>  8) & 0xff] ^
00204             C7[(int)(state[4]      ) & 0xff] ^
00205             K[3];
00206         L[4] =
00207             C0[(int)(state[4] >> 56)       ] ^
00208             C1[(int)(state[3] >> 48) & 0xff] ^
00209             C2[(int)(state[2] >> 40) & 0xff] ^
00210             C3[(int)(state[1] >> 32) & 0xff] ^
00211             C4[(int)(state[0] >> 24) & 0xff] ^
00212             C5[(int)(state[7] >> 16) & 0xff] ^
00213             C6[(int)(state[6] >>  8) & 0xff] ^
00214             C7[(int)(state[5]      ) & 0xff] ^
00215             K[4];
00216         L[5] =
00217             C0[(int)(state[5] >> 56)       ] ^
00218             C1[(int)(state[4] >> 48) & 0xff] ^
00219             C2[(int)(state[3] >> 40) & 0xff] ^
00220             C3[(int)(state[2] >> 32) & 0xff] ^
00221             C4[(int)(state[1] >> 24) & 0xff] ^
00222             C5[(int)(state[0] >> 16) & 0xff] ^
00223             C6[(int)(state[7] >>  8) & 0xff] ^
00224             C7[(int)(state[6]      ) & 0xff] ^
00225             K[5];
00226         L[6] =
00227             C0[(int)(state[6] >> 56)       ] ^
00228             C1[(int)(state[5] >> 48) & 0xff] ^
00229             C2[(int)(state[4] >> 40) & 0xff] ^
00230             C3[(int)(state[3] >> 32) & 0xff] ^
00231             C4[(int)(state[2] >> 24) & 0xff] ^
00232             C5[(int)(state[1] >> 16) & 0xff] ^
00233             C6[(int)(state[0] >>  8) & 0xff] ^
00234             C7[(int)(state[7]      ) & 0xff] ^
00235             K[6];
00236         L[7] =
00237             C0[(int)(state[7] >> 56)       ] ^
00238             C1[(int)(state[6] >> 48) & 0xff] ^
00239             C2[(int)(state[5] >> 40) & 0xff] ^
00240             C3[(int)(state[4] >> 32) & 0xff] ^
00241             C4[(int)(state[3] >> 24) & 0xff] ^
00242             C5[(int)(state[2] >> 16) & 0xff] ^
00243             C6[(int)(state[1] >>  8) & 0xff] ^
00244             C7[(int)(state[0]      ) & 0xff] ^
00245             K[7];
00246         state[0] = L[0];
00247         state[1] = L[1];
00248         state[2] = L[2];
00249         state[3] = L[3];
00250         state[4] = L[4];
00251         state[5] = L[5];
00252         state[6] = L[6];
00253         state[7] = L[7];
00254     }
00255     /*
00256      * apply the Miyaguchi-Preneel compression function:
00257      */
00258     context->state[0] ^= state[0] ^ block[0];
00259     context->state[1] ^= state[1] ^ block[1];
00260     context->state[2] ^= state[2] ^ block[2];
00261     context->state[3] ^= state[3] ^ block[3];
00262     context->state[4] ^= state[4] ^ block[4];
00263     context->state[5] ^= state[5] ^ block[5];
00264     context->state[6] ^= state[6] ^ block[6];
00265     context->state[7] ^= state[7] ^ block[7];
00266     
00267     memset(state, 0, sizeof(state));
00268 }
00269 
00270 PHP_HASH_API void PHP_WHIRLPOOLInit(PHP_WHIRLPOOL_CTX *context)
00271 {
00272        memset(context, 0, sizeof(*context));
00273 }
00274 
00275 PHP_HASH_API void PHP_WHIRLPOOLUpdate(PHP_WHIRLPOOL_CTX *context, const unsigned char *input, size_t len)
00276 {
00277     php_hash_uint64 sourceBits = len * 8;
00278     int sourcePos    = 0; /* index of leftmost source unsigned char containing data (1 to 8 bits). */
00279     int sourceGap    = (8 - ((int)sourceBits & 7)) & 7; /* space on source[sourcePos]. */
00280     int bufferRem    = context->buffer.bits & 7; /* occupied bits on buffer[bufferPos]. */
00281     const unsigned char *source = input;
00282     unsigned char *buffer       = context->buffer.data;
00283     unsigned char *bitLength    = context->bitlength;
00284     int bufferBits   = context->buffer.bits;
00285     int bufferPos    = context->buffer.pos;
00286     php_hash_uint32 b, carry;
00287     int i;
00288 
00289     /*
00290      * tally the length of the added data:
00291      */
00292     php_hash_uint64 value = sourceBits;
00293     for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != L64(0)); i--) {
00294         carry += bitLength[i] + ((php_hash_uint32)value & 0xff);
00295         bitLength[i] = (unsigned char)carry;
00296         carry >>= 8;
00297         value >>= 8;
00298     }
00299     /*
00300      * process data in chunks of 8 bits (a more efficient approach would be to take whole-word chunks):
00301      */
00302     while (sourceBits > 8) {
00303         /* N.B. at least source[sourcePos] and source[sourcePos+1] contain data. */
00304         /*
00305          * take a byte from the source:
00306          */
00307         b = ((source[sourcePos] << sourceGap) & 0xff) |
00308             ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
00309         /*
00310          * process this byte:
00311          */
00312         buffer[bufferPos++] |= (unsigned char)(b >> bufferRem);
00313         bufferBits += 8 - bufferRem; /* bufferBits = 8*bufferPos; */
00314         if (bufferBits == DIGESTBITS) {
00315             /*
00316              * process data block:
00317              */
00318             WhirlpoolTransform(context);
00319             /*
00320              * reset buffer:
00321              */
00322             bufferBits = bufferPos = 0;
00323         }
00324         buffer[bufferPos] = (unsigned char) (b << (8 - bufferRem));
00325         bufferBits += bufferRem;
00326         /*
00327          * proceed to remaining data:
00328          */
00329         sourceBits -= 8;
00330         sourcePos++;
00331     }
00332     /* now 0 <= sourceBits <= 8;
00333      * furthermore, all data (if any is left) is in source[sourcePos].
00334      */
00335     if (sourceBits > 0) {
00336         b = (source[sourcePos] << sourceGap) & 0xff; /* bits are left-justified on b. */
00337         /*
00338          * process the remaining bits:
00339          */
00340         buffer[bufferPos] |= b >> bufferRem;
00341     } else {
00342         b = 0;
00343     }
00344     if (bufferRem + sourceBits < 8) {
00345         /*
00346          * all remaining data fits on buffer[bufferPos],
00347          * and there still remains some space.
00348          */
00349         bufferBits += (int) sourceBits;
00350     } else {
00351         /*
00352          * buffer[bufferPos] is full:
00353          */
00354         bufferPos++;
00355         bufferBits += 8 - bufferRem; /* bufferBits = 8*bufferPos; */
00356         sourceBits -= 8 - bufferRem;
00357         /* now 0 <= sourceBits < 8;
00358          * furthermore, all data (if any is left) is in source[sourcePos].
00359          */
00360         if (bufferBits == DIGESTBITS) {
00361             /*
00362              * process data block:
00363              */
00364             WhirlpoolTransform(context);
00365             /*
00366              * reset buffer:
00367              */
00368             bufferBits = bufferPos = 0;
00369         }
00370         buffer[bufferPos] = (unsigned char) (b << (8 - bufferRem));
00371         bufferBits += (int)sourceBits;
00372     }
00373     context->buffer.bits   = bufferBits;
00374     context->buffer.pos    = bufferPos;
00375 }
00376 
00377 PHP_HASH_API void PHP_WHIRLPOOLFinal(unsigned char digest[64], PHP_WHIRLPOOL_CTX *context)
00378 {
00379     int i;
00380     unsigned char *buffer      = context->buffer.data;
00381     unsigned char *bitLength   = context->bitlength;
00382     int bufferBits  = context->buffer.bits;
00383     int bufferPos   = context->buffer.pos;
00384 
00385     /*
00386      * append a '1'-bit:
00387      */
00388     buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
00389     bufferPos++; /* all remaining bits on the current unsigned char are set to zero. */
00390     /*
00391      * pad with zero bits to complete (N*WBLOCKBITS - LENGTHBITS) bits:
00392      */
00393     if (bufferPos > WBLOCKBYTES - LENGTHBYTES) {
00394         if (bufferPos < WBLOCKBYTES) {
00395             memset(&buffer[bufferPos], 0, WBLOCKBYTES - bufferPos);
00396         }
00397         /*
00398          * process data block:
00399          */
00400         WhirlpoolTransform(context);
00401         /*
00402          * reset buffer:
00403          */
00404         bufferPos = 0;
00405     }
00406     if (bufferPos < WBLOCKBYTES - LENGTHBYTES) {
00407         memset(&buffer[bufferPos], 0, (WBLOCKBYTES - LENGTHBYTES) - bufferPos);
00408     }
00409     bufferPos = WBLOCKBYTES - LENGTHBYTES;
00410     /*
00411      * append bit length of hashed data:
00412      */
00413     memcpy(&buffer[WBLOCKBYTES - LENGTHBYTES], bitLength, LENGTHBYTES);
00414     /*
00415      * process data block:
00416      */
00417     WhirlpoolTransform(context);
00418     /*
00419      * return the completed message digest:
00420      */
00421     for (i = 0; i < DIGESTBYTES/8; i++) {
00422         digest[0] = (unsigned char)(context->state[i] >> 56);
00423         digest[1] = (unsigned char)(context->state[i] >> 48);
00424         digest[2] = (unsigned char)(context->state[i] >> 40);
00425         digest[3] = (unsigned char)(context->state[i] >> 32);
00426         digest[4] = (unsigned char)(context->state[i] >> 24);
00427         digest[5] = (unsigned char)(context->state[i] >> 16);
00428         digest[6] = (unsigned char)(context->state[i] >>  8);
00429         digest[7] = (unsigned char)(context->state[i]      );
00430         digest += 8;
00431     }
00432     
00433     memset(context, 0, sizeof(*context));
00434 }
00435 
00436 const php_hash_ops php_hash_whirlpool_ops = {
00437        (php_hash_init_func_t) PHP_WHIRLPOOLInit,
00438        (php_hash_update_func_t) PHP_WHIRLPOOLUpdate,
00439        (php_hash_final_func_t) PHP_WHIRLPOOLFinal,
00440        (php_hash_copy_func_t) php_hash_copy,
00441        64,
00442        64,
00443        sizeof(PHP_WHIRLPOOL_CTX)
00444 };
00445 
00446 /*
00447  * Local variables:
00448  * tab-width: 4
00449  * c-basic-offset: 4
00450  * End:
00451  * vim600: sw=4 ts=4 fdm=marker
00452  * vim<600: sw=4 ts=4
00453  */