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