1 /* 2 * Copyright 2005-2020 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /** 11 * The Whirlpool hashing function. 12 * 13 * See 14 * P.S.L.M. Barreto, V. Rijmen, 15 * ``The Whirlpool hashing function,'' 16 * NESSIE submission, 2000 (tweaked version, 2001), 17 * <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip> 18 * 19 * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and 20 * Vincent Rijmen. Lookup "reference implementations" on 21 * <http://planeta.terra.com.br/informatica/paulobarreto/> 22 * 23 * ============================================================================= 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 32 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 34 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 */ 38 39 /* 40 * OpenSSL-specific implementation notes. 41 * 42 * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect 43 * number of *bytes* as input length argument. Bit-oriented routine 44 * as specified by authors is called WHIRLPOOL_BitUpdate[!] and 45 * does not have one-stroke counterpart. 46 * 47 * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially 48 * to serve WHIRLPOOL_Update. This is done for performance. 49 * 50 * Unlike authors' reference implementation, block processing 51 * routine whirlpool_block is designed to operate on multi-block 52 * input. This is done for performance. 53 */ 54 55 /* 56 * Whirlpool low level APIs are deprecated for public use, but still ok for 57 * internal use. 58 */ 59 #include "internal/deprecated.h" 60 61 #include <openssl/crypto.h> 62 #include "wp_local.h" 63 #include <string.h> 64 65 int WHIRLPOOL_Init(WHIRLPOOL_CTX *c) 66 { 67 memset(c, 0, sizeof(*c)); 68 return 1; 69 } 70 71 int WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes) 72 { 73 /* 74 * Well, largest suitable chunk size actually is 75 * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not 76 * to care about excessive calls to WHIRLPOOL_BitUpdate... 77 */ 78 size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4); 79 const unsigned char *inp = _inp; 80 81 while (bytes >= chunk) { 82 WHIRLPOOL_BitUpdate(c, inp, chunk * 8); 83 bytes -= chunk; 84 inp += chunk; 85 } 86 if (bytes) 87 WHIRLPOOL_BitUpdate(c, inp, bytes * 8); 88 89 return 1; 90 } 91 92 void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits) 93 { 94 size_t n; 95 unsigned int bitoff = c->bitoff, 96 bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7; 97 const unsigned char *inp = _inp; 98 99 /* 100 * This 256-bit increment procedure relies on the size_t being natural 101 * size of CPU register, so that we don't have to mask the value in order 102 * to detect overflows. 103 */ 104 c->bitlen[0] += bits; 105 if (c->bitlen[0] < bits) { /* overflow */ 106 n = 1; 107 do { 108 c->bitlen[n]++; 109 } while (c->bitlen[n] == 0 110 && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t))); 111 } 112 #ifndef OPENSSL_SMALL_FOOTPRINT 113 reconsider: 114 if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */ 115 while (bits) { 116 if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) { 117 whirlpool_block(c, inp, n); 118 inp += n * WHIRLPOOL_BBLOCK / 8; 119 bits %= WHIRLPOOL_BBLOCK; 120 } else { 121 unsigned int byteoff = bitoff / 8; 122 123 bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */ 124 if (bits >= bitrem) { 125 bits -= bitrem; 126 bitrem /= 8; 127 memcpy(c->data + byteoff, inp, bitrem); 128 inp += bitrem; 129 whirlpool_block(c, c->data, 1); 130 bitoff = 0; 131 } else { 132 memcpy(c->data + byteoff, inp, bits / 8); 133 bitoff += (unsigned int)bits; 134 bits = 0; 135 } 136 c->bitoff = bitoff; 137 } 138 } 139 } else /* bit-oriented loop */ 140 #endif 141 { 142 /*- 143 inp 144 | 145 +-------+-------+------- 146 ||||||||||||||||||||| 147 +-------+-------+------- 148 +-------+-------+-------+-------+------- 149 |||||||||||||| c->data 150 +-------+-------+-------+-------+------- 151 | 152 c->bitoff/8 153 */ 154 while (bits) { 155 unsigned int byteoff = bitoff / 8; 156 unsigned char b; 157 158 #ifndef OPENSSL_SMALL_FOOTPRINT 159 if (bitrem == inpgap) { 160 c->data[byteoff++] |= inp[0] & (0xff >> inpgap); 161 inpgap = 8 - inpgap; 162 bitoff += inpgap; 163 bitrem = 0; /* bitoff%8 */ 164 bits -= inpgap; 165 inpgap = 0; /* bits%8 */ 166 inp++; 167 if (bitoff == WHIRLPOOL_BBLOCK) { 168 whirlpool_block(c, c->data, 1); 169 bitoff = 0; 170 } 171 c->bitoff = bitoff; 172 goto reconsider; 173 } else 174 #endif 175 if (bits > 8) { 176 b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap))); 177 b &= 0xff; 178 if (bitrem) 179 c->data[byteoff++] |= b >> bitrem; 180 else 181 c->data[byteoff++] = b; 182 bitoff += 8; 183 bits -= 8; 184 inp++; 185 if (bitoff >= WHIRLPOOL_BBLOCK) { 186 whirlpool_block(c, c->data, 1); 187 byteoff = 0; 188 bitoff %= WHIRLPOOL_BBLOCK; 189 } 190 if (bitrem) 191 c->data[byteoff] = b << (8 - bitrem); 192 } else { /* remaining less than or equal to 8 bits */ 193 194 b = (inp[0] << inpgap) & 0xff; 195 if (bitrem) 196 c->data[byteoff++] |= b >> bitrem; 197 else 198 c->data[byteoff++] = b; 199 bitoff += (unsigned int)bits; 200 if (bitoff == WHIRLPOOL_BBLOCK) { 201 whirlpool_block(c, c->data, 1); 202 byteoff = 0; 203 bitoff %= WHIRLPOOL_BBLOCK; 204 } 205 if (bitrem) 206 c->data[byteoff] = b << (8 - bitrem); 207 bits = 0; 208 } 209 c->bitoff = bitoff; 210 } 211 } 212 } 213 214 int WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c) 215 { 216 unsigned int bitoff = c->bitoff, byteoff = bitoff / 8; 217 size_t i, j, v; 218 unsigned char *p; 219 220 bitoff %= 8; 221 if (bitoff) 222 c->data[byteoff] |= 0x80 >> bitoff; 223 else 224 c->data[byteoff] = 0x80; 225 byteoff++; 226 227 /* pad with zeros */ 228 if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) { 229 if (byteoff < WHIRLPOOL_BBLOCK / 8) 230 memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff); 231 whirlpool_block(c, c->data, 1); 232 byteoff = 0; 233 } 234 if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) 235 memset(&c->data[byteoff], 0, 236 (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff); 237 /* smash 256-bit c->bitlen in big-endian order */ 238 p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */ 239 for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++) 240 for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8) 241 *p-- = (unsigned char)(v & 0xff); 242 243 whirlpool_block(c, c->data, 1); 244 245 if (md) { 246 memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH); 247 OPENSSL_cleanse(c, sizeof(*c)); 248 return 1; 249 } 250 return 0; 251 } 252 253 unsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md) 254 { 255 WHIRLPOOL_CTX ctx; 256 static unsigned char m[WHIRLPOOL_DIGEST_LENGTH]; 257 258 if (md == NULL) 259 md = m; 260 WHIRLPOOL_Init(&ctx); 261 WHIRLPOOL_Update(&ctx, inp, bytes); 262 WHIRLPOOL_Final(md, &ctx); 263 return md; 264 } 265