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 54306195Sjkim#include <openssl/crypto.h> 55238384Sjkim#include "wp_locl.h" 56238384Sjkim#include <openssl/crypto.h> 57238384Sjkim#include <string.h> 58238384Sjkim 59238384Sjkimfips_md_init(WHIRLPOOL) 60280297Sjkim{ 61280297Sjkim memset(c, 0, sizeof(*c)); 62280297Sjkim return (1); 63280297Sjkim} 64238384Sjkim 65280297Sjkimint WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes) 66280297Sjkim{ 67280297Sjkim /* 68280297Sjkim * Well, largest suitable chunk size actually is 69280297Sjkim * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not 70280297Sjkim * to care about excessive calls to WHIRLPOOL_BitUpdate... 71280297Sjkim */ 72280297Sjkim size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4); 73280297Sjkim const unsigned char *inp = _inp; 74238384Sjkim 75280297Sjkim while (bytes >= chunk) { 76280297Sjkim WHIRLPOOL_BitUpdate(c, inp, chunk * 8); 77280297Sjkim bytes -= chunk; 78280297Sjkim inp += chunk; 79280297Sjkim } 80280297Sjkim if (bytes) 81280297Sjkim WHIRLPOOL_BitUpdate(c, inp, bytes * 8); 82238384Sjkim 83280297Sjkim return (1); 84280297Sjkim} 85238384Sjkim 86280297Sjkimvoid WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits) 87280297Sjkim{ 88280297Sjkim size_t n; 89280297Sjkim unsigned int bitoff = c->bitoff, 90280297Sjkim bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7; 91280297Sjkim const unsigned char *inp = _inp; 92238384Sjkim 93280297Sjkim /* 94280297Sjkim * This 256-bit increment procedure relies on the size_t being natural 95280297Sjkim * size of CPU register, so that we don't have to mask the value in order 96280297Sjkim * to detect overflows. 97280297Sjkim */ 98280297Sjkim c->bitlen[0] += bits; 99280297Sjkim if (c->bitlen[0] < bits) { /* overflow */ 100280297Sjkim n = 1; 101280297Sjkim do { 102280297Sjkim c->bitlen[n]++; 103280297Sjkim } while (c->bitlen[n] == 0 104280297Sjkim && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t))); 105280297Sjkim } 106238384Sjkim#ifndef OPENSSL_SMALL_FOOTPRINT 107280297Sjkim reconsider: 108280297Sjkim if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */ 109280297Sjkim while (bits) { 110280297Sjkim if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) { 111280297Sjkim whirlpool_block(c, inp, n); 112280297Sjkim inp += n * WHIRLPOOL_BBLOCK / 8; 113280297Sjkim bits %= WHIRLPOOL_BBLOCK; 114280297Sjkim } else { 115280297Sjkim unsigned int byteoff = bitoff / 8; 116238384Sjkim 117280297Sjkim bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */ 118280297Sjkim if (bits >= bitrem) { 119280297Sjkim bits -= bitrem; 120280297Sjkim bitrem /= 8; 121280297Sjkim memcpy(c->data + byteoff, inp, bitrem); 122280297Sjkim inp += bitrem; 123280297Sjkim whirlpool_block(c, c->data, 1); 124280297Sjkim bitoff = 0; 125280297Sjkim } else { 126280297Sjkim memcpy(c->data + byteoff, inp, bits / 8); 127280297Sjkim bitoff += (unsigned int)bits; 128280297Sjkim bits = 0; 129280297Sjkim } 130280297Sjkim c->bitoff = bitoff; 131280297Sjkim } 132280297Sjkim } 133280297Sjkim } else /* bit-oriented loop */ 134238384Sjkim#endif 135280297Sjkim { 136280297Sjkim /*- 137280297Sjkim inp 138280297Sjkim | 139280297Sjkim +-------+-------+------- 140280297Sjkim ||||||||||||||||||||| 141280297Sjkim +-------+-------+------- 142280297Sjkim +-------+-------+-------+-------+------- 143280297Sjkim |||||||||||||| c->data 144280297Sjkim +-------+-------+-------+-------+------- 145280297Sjkim | 146280297Sjkim c->bitoff/8 147280297Sjkim */ 148280297Sjkim while (bits) { 149280297Sjkim unsigned int byteoff = bitoff / 8; 150280297Sjkim unsigned char b; 151238384Sjkim 152238384Sjkim#ifndef OPENSSL_SMALL_FOOTPRINT 153280297Sjkim if (bitrem == inpgap) { 154280297Sjkim c->data[byteoff++] |= inp[0] & (0xff >> inpgap); 155280297Sjkim inpgap = 8 - inpgap; 156280297Sjkim bitoff += inpgap; 157280297Sjkim bitrem = 0; /* bitoff%8 */ 158280297Sjkim bits -= inpgap; 159280297Sjkim inpgap = 0; /* bits%8 */ 160280297Sjkim inp++; 161280297Sjkim if (bitoff == WHIRLPOOL_BBLOCK) { 162280297Sjkim whirlpool_block(c, c->data, 1); 163280297Sjkim bitoff = 0; 164280297Sjkim } 165280297Sjkim c->bitoff = bitoff; 166280297Sjkim goto reconsider; 167280297Sjkim } else 168238384Sjkim#endif 169325337Sjkim if (bits > 8) { 170280297Sjkim b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap))); 171280297Sjkim b &= 0xff; 172280297Sjkim if (bitrem) 173280297Sjkim c->data[byteoff++] |= b >> bitrem; 174280297Sjkim else 175280297Sjkim c->data[byteoff++] = b; 176280297Sjkim bitoff += 8; 177280297Sjkim bits -= 8; 178280297Sjkim inp++; 179280297Sjkim if (bitoff >= WHIRLPOOL_BBLOCK) { 180280297Sjkim whirlpool_block(c, c->data, 1); 181280297Sjkim byteoff = 0; 182280297Sjkim bitoff %= WHIRLPOOL_BBLOCK; 183280297Sjkim } 184280297Sjkim if (bitrem) 185280297Sjkim c->data[byteoff] = b << (8 - bitrem); 186325337Sjkim } else { /* remaining less than or equal to 8 bits */ 187238384Sjkim 188280297Sjkim b = (inp[0] << inpgap) & 0xff; 189280297Sjkim if (bitrem) 190280297Sjkim c->data[byteoff++] |= b >> bitrem; 191280297Sjkim else 192280297Sjkim c->data[byteoff++] = b; 193280297Sjkim bitoff += (unsigned int)bits; 194280297Sjkim if (bitoff == WHIRLPOOL_BBLOCK) { 195280297Sjkim whirlpool_block(c, c->data, 1); 196280297Sjkim byteoff = 0; 197280297Sjkim bitoff %= WHIRLPOOL_BBLOCK; 198280297Sjkim } 199280297Sjkim if (bitrem) 200280297Sjkim c->data[byteoff] = b << (8 - bitrem); 201280297Sjkim bits = 0; 202280297Sjkim } 203280297Sjkim c->bitoff = bitoff; 204280297Sjkim } 205280297Sjkim } 206280297Sjkim} 207238384Sjkim 208280297Sjkimint WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c) 209280297Sjkim{ 210280297Sjkim unsigned int bitoff = c->bitoff, byteoff = bitoff / 8; 211280297Sjkim size_t i, j, v; 212280297Sjkim unsigned char *p; 213238384Sjkim 214280297Sjkim bitoff %= 8; 215280297Sjkim if (bitoff) 216280297Sjkim c->data[byteoff] |= 0x80 >> bitoff; 217280297Sjkim else 218280297Sjkim c->data[byteoff] = 0x80; 219280297Sjkim byteoff++; 220238384Sjkim 221280297Sjkim /* pad with zeros */ 222280297Sjkim if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) { 223280297Sjkim if (byteoff < WHIRLPOOL_BBLOCK / 8) 224280297Sjkim memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff); 225280297Sjkim whirlpool_block(c, c->data, 1); 226280297Sjkim byteoff = 0; 227280297Sjkim } 228280297Sjkim if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) 229280297Sjkim memset(&c->data[byteoff], 0, 230280297Sjkim (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff); 231280297Sjkim /* smash 256-bit c->bitlen in big-endian order */ 232280297Sjkim p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */ 233280297Sjkim for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++) 234280297Sjkim for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8) 235280297Sjkim *p-- = (unsigned char)(v & 0xff); 236238384Sjkim 237280297Sjkim whirlpool_block(c, c->data, 1); 238238384Sjkim 239280297Sjkim if (md) { 240280297Sjkim memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH); 241306195Sjkim OPENSSL_cleanse(c, sizeof(*c)); 242280297Sjkim return (1); 243280297Sjkim } 244280297Sjkim return (0); 245280297Sjkim} 246238384Sjkim 247280297Sjkimunsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md) 248280297Sjkim{ 249280297Sjkim WHIRLPOOL_CTX ctx; 250280297Sjkim static unsigned char m[WHIRLPOOL_DIGEST_LENGTH]; 251280297Sjkim 252280297Sjkim if (md == NULL) 253280297Sjkim md = m; 254280297Sjkim WHIRLPOOL_Init(&ctx); 255280297Sjkim WHIRLPOOL_Update(&ctx, inp, bytes); 256280297Sjkim WHIRLPOOL_Final(md, &ctx); 257280297Sjkim return (md); 258280297Sjkim} 259