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