1238384Sjkim/** 2238384Sjkim * The Whirlpool hashing function. 3238384Sjkim * 4238384Sjkim * <P> 5238384Sjkim * <b>References</b> 6238384Sjkim * 7238384Sjkim * <P> 8238384Sjkim * The Whirlpool algorithm was developed by 9238384Sjkim * <a href="mailto:pbarreto@scopus.com.br">Paulo S. L. M. Barreto</a> and 10238384Sjkim * <a href="mailto:vincent.rijmen@cryptomathic.com">Vincent Rijmen</a>. 11238384Sjkim * 12238384Sjkim * See 13238384Sjkim * P.S.L.M. Barreto, V. Rijmen, 14238384Sjkim * ``The Whirlpool hashing function,'' 15238384Sjkim * NESSIE submission, 2000 (tweaked version, 2001), 16238384Sjkim * <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip> 17238384Sjkim * 18238384Sjkim * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and 19238384Sjkim * Vincent Rijmen. Lookup "reference implementations" on 20238384Sjkim * <http://planeta.terra.com.br/informatica/paulobarreto/> 21238384Sjkim * 22238384Sjkim * ============================================================================= 23238384Sjkim * 24238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 25238384Sjkim * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26238384Sjkim * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27238384Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 28238384Sjkim * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29238384Sjkim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30238384Sjkim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 31238384Sjkim * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32238384Sjkim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33238384Sjkim * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 34238384Sjkim * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35238384Sjkim * 36238384Sjkim */ 37238384Sjkim 38238384Sjkim/* 39238384Sjkim * OpenSSL-specific implementation notes. 40238384Sjkim * 41238384Sjkim * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect 42238384Sjkim * number of *bytes* as input length argument. Bit-oriented routine 43238384Sjkim * as specified by authors is called WHIRLPOOL_BitUpdate[!] and 44238384Sjkim * does not have one-stroke counterpart. 45238384Sjkim * 46238384Sjkim * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially 47238384Sjkim * to serve WHIRLPOOL_Update. This is done for performance. 48238384Sjkim * 49238384Sjkim * Unlike authors' reference implementation, block processing 50238384Sjkim * routine whirlpool_block is designed to operate on multi-block 51238384Sjkim * input. This is done for perfomance. 52238384Sjkim */ 53238384Sjkim 54306196Sjkim#include <openssl/crypto.h> 55238384Sjkim#include "wp_locl.h" 56238384Sjkim#include <openssl/crypto.h> 57238384Sjkim#include <string.h> 58238384Sjkim 59238384Sjkimfips_md_init(WHIRLPOOL) 60280304Sjkim{ 61280304Sjkim memset(c, 0, sizeof(*c)); 62280304Sjkim return (1); 63280304Sjkim} 64238384Sjkim 65280304Sjkimint WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes) 66280304Sjkim{ 67280304Sjkim /* 68280304Sjkim * Well, largest suitable chunk size actually is 69280304Sjkim * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not 70280304Sjkim * to care about excessive calls to WHIRLPOOL_BitUpdate... 71280304Sjkim */ 72280304Sjkim size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4); 73280304Sjkim const unsigned char *inp = _inp; 74238384Sjkim 75280304Sjkim while (bytes >= chunk) { 76280304Sjkim WHIRLPOOL_BitUpdate(c, inp, chunk * 8); 77280304Sjkim bytes -= chunk; 78280304Sjkim inp += chunk; 79280304Sjkim } 80280304Sjkim if (bytes) 81280304Sjkim WHIRLPOOL_BitUpdate(c, inp, bytes * 8); 82238384Sjkim 83280304Sjkim return (1); 84280304Sjkim} 85238384Sjkim 86280304Sjkimvoid WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits) 87280304Sjkim{ 88280304Sjkim size_t n; 89280304Sjkim unsigned int bitoff = c->bitoff, 90280304Sjkim bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7; 91280304Sjkim const unsigned char *inp = _inp; 92238384Sjkim 93280304Sjkim /* 94280304Sjkim * This 256-bit increment procedure relies on the size_t being natural 95280304Sjkim * size of CPU register, so that we don't have to mask the value in order 96280304Sjkim * to detect overflows. 97280304Sjkim */ 98280304Sjkim c->bitlen[0] += bits; 99280304Sjkim if (c->bitlen[0] < bits) { /* overflow */ 100280304Sjkim n = 1; 101280304Sjkim do { 102280304Sjkim c->bitlen[n]++; 103280304Sjkim } while (c->bitlen[n] == 0 104280304Sjkim && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t))); 105280304Sjkim } 106238384Sjkim#ifndef OPENSSL_SMALL_FOOTPRINT 107280304Sjkim reconsider: 108280304Sjkim if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */ 109280304Sjkim while (bits) { 110280304Sjkim if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) { 111280304Sjkim whirlpool_block(c, inp, n); 112280304Sjkim inp += n * WHIRLPOOL_BBLOCK / 8; 113280304Sjkim bits %= WHIRLPOOL_BBLOCK; 114280304Sjkim } else { 115280304Sjkim unsigned int byteoff = bitoff / 8; 116238384Sjkim 117280304Sjkim bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */ 118280304Sjkim if (bits >= bitrem) { 119280304Sjkim bits -= bitrem; 120280304Sjkim bitrem /= 8; 121280304Sjkim memcpy(c->data + byteoff, inp, bitrem); 122280304Sjkim inp += bitrem; 123280304Sjkim whirlpool_block(c, c->data, 1); 124280304Sjkim bitoff = 0; 125280304Sjkim } else { 126280304Sjkim memcpy(c->data + byteoff, inp, bits / 8); 127280304Sjkim bitoff += (unsigned int)bits; 128280304Sjkim bits = 0; 129280304Sjkim } 130280304Sjkim c->bitoff = bitoff; 131280304Sjkim } 132280304Sjkim } 133280304Sjkim } else /* bit-oriented loop */ 134238384Sjkim#endif 135280304Sjkim { 136280304Sjkim /*- 137280304Sjkim inp 138280304Sjkim | 139280304Sjkim +-------+-------+------- 140280304Sjkim ||||||||||||||||||||| 141280304Sjkim +-------+-------+------- 142280304Sjkim +-------+-------+-------+-------+------- 143280304Sjkim |||||||||||||| c->data 144280304Sjkim +-------+-------+-------+-------+------- 145280304Sjkim | 146280304Sjkim c->bitoff/8 147280304Sjkim */ 148280304Sjkim while (bits) { 149280304Sjkim unsigned int byteoff = bitoff / 8; 150280304Sjkim unsigned char b; 151238384Sjkim 152238384Sjkim#ifndef OPENSSL_SMALL_FOOTPRINT 153280304Sjkim if (bitrem == inpgap) { 154280304Sjkim c->data[byteoff++] |= inp[0] & (0xff >> inpgap); 155280304Sjkim inpgap = 8 - inpgap; 156280304Sjkim bitoff += inpgap; 157280304Sjkim bitrem = 0; /* bitoff%8 */ 158280304Sjkim bits -= inpgap; 159280304Sjkim inpgap = 0; /* bits%8 */ 160280304Sjkim inp++; 161280304Sjkim if (bitoff == WHIRLPOOL_BBLOCK) { 162280304Sjkim whirlpool_block(c, c->data, 1); 163280304Sjkim bitoff = 0; 164280304Sjkim } 165280304Sjkim c->bitoff = bitoff; 166280304Sjkim goto reconsider; 167280304Sjkim } else 168238384Sjkim#endif 169280304Sjkim if (bits >= 8) { 170280304Sjkim b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap))); 171280304Sjkim b &= 0xff; 172280304Sjkim if (bitrem) 173280304Sjkim c->data[byteoff++] |= b >> bitrem; 174280304Sjkim else 175280304Sjkim c->data[byteoff++] = b; 176280304Sjkim bitoff += 8; 177280304Sjkim bits -= 8; 178280304Sjkim inp++; 179280304Sjkim if (bitoff >= WHIRLPOOL_BBLOCK) { 180280304Sjkim whirlpool_block(c, c->data, 1); 181280304Sjkim byteoff = 0; 182280304Sjkim bitoff %= WHIRLPOOL_BBLOCK; 183280304Sjkim } 184280304Sjkim if (bitrem) 185280304Sjkim c->data[byteoff] = b << (8 - bitrem); 186280304Sjkim } else { /* remaining less than 8 bits */ 187238384Sjkim 188280304Sjkim b = (inp[0] << inpgap) & 0xff; 189280304Sjkim if (bitrem) 190280304Sjkim c->data[byteoff++] |= b >> bitrem; 191280304Sjkim else 192280304Sjkim c->data[byteoff++] = b; 193280304Sjkim bitoff += (unsigned int)bits; 194280304Sjkim if (bitoff == WHIRLPOOL_BBLOCK) { 195280304Sjkim whirlpool_block(c, c->data, 1); 196280304Sjkim byteoff = 0; 197280304Sjkim bitoff %= WHIRLPOOL_BBLOCK; 198280304Sjkim } 199280304Sjkim if (bitrem) 200280304Sjkim c->data[byteoff] = b << (8 - bitrem); 201280304Sjkim bits = 0; 202280304Sjkim } 203280304Sjkim c->bitoff = bitoff; 204280304Sjkim } 205280304Sjkim } 206280304Sjkim} 207238384Sjkim 208280304Sjkimint WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c) 209280304Sjkim{ 210280304Sjkim unsigned int bitoff = c->bitoff, byteoff = bitoff / 8; 211280304Sjkim size_t i, j, v; 212280304Sjkim unsigned char *p; 213238384Sjkim 214280304Sjkim bitoff %= 8; 215280304Sjkim if (bitoff) 216280304Sjkim c->data[byteoff] |= 0x80 >> bitoff; 217280304Sjkim else 218280304Sjkim c->data[byteoff] = 0x80; 219280304Sjkim byteoff++; 220238384Sjkim 221280304Sjkim /* pad with zeros */ 222280304Sjkim if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) { 223280304Sjkim if (byteoff < WHIRLPOOL_BBLOCK / 8) 224280304Sjkim memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff); 225280304Sjkim whirlpool_block(c, c->data, 1); 226280304Sjkim byteoff = 0; 227280304Sjkim } 228280304Sjkim if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) 229280304Sjkim memset(&c->data[byteoff], 0, 230280304Sjkim (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff); 231280304Sjkim /* smash 256-bit c->bitlen in big-endian order */ 232280304Sjkim p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */ 233280304Sjkim for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++) 234280304Sjkim for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8) 235280304Sjkim *p-- = (unsigned char)(v & 0xff); 236238384Sjkim 237280304Sjkim whirlpool_block(c, c->data, 1); 238238384Sjkim 239280304Sjkim if (md) { 240280304Sjkim memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH); 241306196Sjkim OPENSSL_cleanse(c, sizeof(*c)); 242280304Sjkim return (1); 243280304Sjkim } 244280304Sjkim return (0); 245280304Sjkim} 246238384Sjkim 247280304Sjkimunsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md) 248280304Sjkim{ 249280304Sjkim WHIRLPOOL_CTX ctx; 250280304Sjkim static unsigned char m[WHIRLPOOL_DIGEST_LENGTH]; 251280304Sjkim 252280304Sjkim if (md == NULL) 253280304Sjkim md = m; 254280304Sjkim WHIRLPOOL_Init(&ctx); 255280304Sjkim WHIRLPOOL_Update(&ctx, inp, bytes); 256280304Sjkim WHIRLPOOL_Final(md, &ctx); 257280304Sjkim return (md); 258280304Sjkim} 259