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