11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 2005-2020 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci/**
111cb0ef41Sopenharmony_ci * The Whirlpool hashing function.
121cb0ef41Sopenharmony_ci *
131cb0ef41Sopenharmony_ci * See
141cb0ef41Sopenharmony_ci *      P.S.L.M. Barreto, V. Rijmen,
151cb0ef41Sopenharmony_ci *      ``The Whirlpool hashing function,''
161cb0ef41Sopenharmony_ci *      NESSIE submission, 2000 (tweaked version, 2001),
171cb0ef41Sopenharmony_ci *      <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
181cb0ef41Sopenharmony_ci *
191cb0ef41Sopenharmony_ci * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and
201cb0ef41Sopenharmony_ci * Vincent Rijmen. Lookup "reference implementations" on
211cb0ef41Sopenharmony_ci * <http://planeta.terra.com.br/informatica/paulobarreto/>
221cb0ef41Sopenharmony_ci *
231cb0ef41Sopenharmony_ci * =============================================================================
241cb0ef41Sopenharmony_ci *
251cb0ef41Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
261cb0ef41Sopenharmony_ci * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
271cb0ef41Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281cb0ef41Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
291cb0ef41Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
301cb0ef41Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
311cb0ef41Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
321cb0ef41Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
331cb0ef41Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
341cb0ef41Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
351cb0ef41Sopenharmony_ci * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361cb0ef41Sopenharmony_ci *
371cb0ef41Sopenharmony_ci */
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci/*
401cb0ef41Sopenharmony_ci * OpenSSL-specific implementation notes.
411cb0ef41Sopenharmony_ci *
421cb0ef41Sopenharmony_ci * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect
431cb0ef41Sopenharmony_ci * number of *bytes* as input length argument. Bit-oriented routine
441cb0ef41Sopenharmony_ci * as specified by authors is called WHIRLPOOL_BitUpdate[!] and
451cb0ef41Sopenharmony_ci * does not have one-stroke counterpart.
461cb0ef41Sopenharmony_ci *
471cb0ef41Sopenharmony_ci * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially
481cb0ef41Sopenharmony_ci * to serve WHIRLPOOL_Update. This is done for performance.
491cb0ef41Sopenharmony_ci *
501cb0ef41Sopenharmony_ci * Unlike authors' reference implementation, block processing
511cb0ef41Sopenharmony_ci * routine whirlpool_block is designed to operate on multi-block
521cb0ef41Sopenharmony_ci * input. This is done for performance.
531cb0ef41Sopenharmony_ci */
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci/*
561cb0ef41Sopenharmony_ci * Whirlpool low level APIs are deprecated for public use, but still ok for
571cb0ef41Sopenharmony_ci * internal use.
581cb0ef41Sopenharmony_ci */
591cb0ef41Sopenharmony_ci#include "internal/deprecated.h"
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci#include <openssl/crypto.h>
621cb0ef41Sopenharmony_ci#include "wp_local.h"
631cb0ef41Sopenharmony_ci#include <string.h>
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ciint WHIRLPOOL_Init(WHIRLPOOL_CTX *c)
661cb0ef41Sopenharmony_ci{
671cb0ef41Sopenharmony_ci    memset(c, 0, sizeof(*c));
681cb0ef41Sopenharmony_ci    return 1;
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ciint WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes)
721cb0ef41Sopenharmony_ci{
731cb0ef41Sopenharmony_ci    /*
741cb0ef41Sopenharmony_ci     * Well, largest suitable chunk size actually is
751cb0ef41Sopenharmony_ci     * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not
761cb0ef41Sopenharmony_ci     * to care about excessive calls to WHIRLPOOL_BitUpdate...
771cb0ef41Sopenharmony_ci     */
781cb0ef41Sopenharmony_ci    size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4);
791cb0ef41Sopenharmony_ci    const unsigned char *inp = _inp;
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    while (bytes >= chunk) {
821cb0ef41Sopenharmony_ci        WHIRLPOOL_BitUpdate(c, inp, chunk * 8);
831cb0ef41Sopenharmony_ci        bytes -= chunk;
841cb0ef41Sopenharmony_ci        inp += chunk;
851cb0ef41Sopenharmony_ci    }
861cb0ef41Sopenharmony_ci    if (bytes)
871cb0ef41Sopenharmony_ci        WHIRLPOOL_BitUpdate(c, inp, bytes * 8);
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    return 1;
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_civoid WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits)
931cb0ef41Sopenharmony_ci{
941cb0ef41Sopenharmony_ci    size_t n;
951cb0ef41Sopenharmony_ci    unsigned int bitoff = c->bitoff,
961cb0ef41Sopenharmony_ci        bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7;
971cb0ef41Sopenharmony_ci    const unsigned char *inp = _inp;
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci    /*
1001cb0ef41Sopenharmony_ci     * This 256-bit increment procedure relies on the size_t being natural
1011cb0ef41Sopenharmony_ci     * size of CPU register, so that we don't have to mask the value in order
1021cb0ef41Sopenharmony_ci     * to detect overflows.
1031cb0ef41Sopenharmony_ci     */
1041cb0ef41Sopenharmony_ci    c->bitlen[0] += bits;
1051cb0ef41Sopenharmony_ci    if (c->bitlen[0] < bits) {  /* overflow */
1061cb0ef41Sopenharmony_ci        n = 1;
1071cb0ef41Sopenharmony_ci        do {
1081cb0ef41Sopenharmony_ci            c->bitlen[n]++;
1091cb0ef41Sopenharmony_ci        } while (c->bitlen[n] == 0
1101cb0ef41Sopenharmony_ci                 && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t)));
1111cb0ef41Sopenharmony_ci    }
1121cb0ef41Sopenharmony_ci#ifndef OPENSSL_SMALL_FOOTPRINT
1131cb0ef41Sopenharmony_ci reconsider:
1141cb0ef41Sopenharmony_ci    if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */
1151cb0ef41Sopenharmony_ci        while (bits) {
1161cb0ef41Sopenharmony_ci            if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) {
1171cb0ef41Sopenharmony_ci                whirlpool_block(c, inp, n);
1181cb0ef41Sopenharmony_ci                inp += n * WHIRLPOOL_BBLOCK / 8;
1191cb0ef41Sopenharmony_ci                bits %= WHIRLPOOL_BBLOCK;
1201cb0ef41Sopenharmony_ci            } else {
1211cb0ef41Sopenharmony_ci                unsigned int byteoff = bitoff / 8;
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci                bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */
1241cb0ef41Sopenharmony_ci                if (bits >= bitrem) {
1251cb0ef41Sopenharmony_ci                    bits -= bitrem;
1261cb0ef41Sopenharmony_ci                    bitrem /= 8;
1271cb0ef41Sopenharmony_ci                    memcpy(c->data + byteoff, inp, bitrem);
1281cb0ef41Sopenharmony_ci                    inp += bitrem;
1291cb0ef41Sopenharmony_ci                    whirlpool_block(c, c->data, 1);
1301cb0ef41Sopenharmony_ci                    bitoff = 0;
1311cb0ef41Sopenharmony_ci                } else {
1321cb0ef41Sopenharmony_ci                    memcpy(c->data + byteoff, inp, bits / 8);
1331cb0ef41Sopenharmony_ci                    bitoff += (unsigned int)bits;
1341cb0ef41Sopenharmony_ci                    bits = 0;
1351cb0ef41Sopenharmony_ci                }
1361cb0ef41Sopenharmony_ci                c->bitoff = bitoff;
1371cb0ef41Sopenharmony_ci            }
1381cb0ef41Sopenharmony_ci        }
1391cb0ef41Sopenharmony_ci    } else                      /* bit-oriented loop */
1401cb0ef41Sopenharmony_ci#endif
1411cb0ef41Sopenharmony_ci    {
1421cb0ef41Sopenharmony_ci        /*-
1431cb0ef41Sopenharmony_ci                   inp
1441cb0ef41Sopenharmony_ci                   |
1451cb0ef41Sopenharmony_ci                   +-------+-------+-------
1461cb0ef41Sopenharmony_ci                      |||||||||||||||||||||
1471cb0ef41Sopenharmony_ci                   +-------+-------+-------
1481cb0ef41Sopenharmony_ci        +-------+-------+-------+-------+-------
1491cb0ef41Sopenharmony_ci        ||||||||||||||                          c->data
1501cb0ef41Sopenharmony_ci        +-------+-------+-------+-------+-------
1511cb0ef41Sopenharmony_ci                |
1521cb0ef41Sopenharmony_ci                c->bitoff/8
1531cb0ef41Sopenharmony_ci        */
1541cb0ef41Sopenharmony_ci        while (bits) {
1551cb0ef41Sopenharmony_ci            unsigned int byteoff = bitoff / 8;
1561cb0ef41Sopenharmony_ci            unsigned char b;
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci#ifndef OPENSSL_SMALL_FOOTPRINT
1591cb0ef41Sopenharmony_ci            if (bitrem == inpgap) {
1601cb0ef41Sopenharmony_ci                c->data[byteoff++] |= inp[0] & (0xff >> inpgap);
1611cb0ef41Sopenharmony_ci                inpgap = 8 - inpgap;
1621cb0ef41Sopenharmony_ci                bitoff += inpgap;
1631cb0ef41Sopenharmony_ci                bitrem = 0;     /* bitoff%8 */
1641cb0ef41Sopenharmony_ci                bits -= inpgap;
1651cb0ef41Sopenharmony_ci                inpgap = 0;     /* bits%8 */
1661cb0ef41Sopenharmony_ci                inp++;
1671cb0ef41Sopenharmony_ci                if (bitoff == WHIRLPOOL_BBLOCK) {
1681cb0ef41Sopenharmony_ci                    whirlpool_block(c, c->data, 1);
1691cb0ef41Sopenharmony_ci                    bitoff = 0;
1701cb0ef41Sopenharmony_ci                }
1711cb0ef41Sopenharmony_ci                c->bitoff = bitoff;
1721cb0ef41Sopenharmony_ci                goto reconsider;
1731cb0ef41Sopenharmony_ci            } else
1741cb0ef41Sopenharmony_ci#endif
1751cb0ef41Sopenharmony_ci            if (bits > 8) {
1761cb0ef41Sopenharmony_ci                b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap)));
1771cb0ef41Sopenharmony_ci                b &= 0xff;
1781cb0ef41Sopenharmony_ci                if (bitrem)
1791cb0ef41Sopenharmony_ci                    c->data[byteoff++] |= b >> bitrem;
1801cb0ef41Sopenharmony_ci                else
1811cb0ef41Sopenharmony_ci                    c->data[byteoff++] = b;
1821cb0ef41Sopenharmony_ci                bitoff += 8;
1831cb0ef41Sopenharmony_ci                bits -= 8;
1841cb0ef41Sopenharmony_ci                inp++;
1851cb0ef41Sopenharmony_ci                if (bitoff >= WHIRLPOOL_BBLOCK) {
1861cb0ef41Sopenharmony_ci                    whirlpool_block(c, c->data, 1);
1871cb0ef41Sopenharmony_ci                    byteoff = 0;
1881cb0ef41Sopenharmony_ci                    bitoff %= WHIRLPOOL_BBLOCK;
1891cb0ef41Sopenharmony_ci                }
1901cb0ef41Sopenharmony_ci                if (bitrem)
1911cb0ef41Sopenharmony_ci                    c->data[byteoff] = b << (8 - bitrem);
1921cb0ef41Sopenharmony_ci            } else {            /* remaining less than or equal to 8 bits */
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci                b = (inp[0] << inpgap) & 0xff;
1951cb0ef41Sopenharmony_ci                if (bitrem)
1961cb0ef41Sopenharmony_ci                    c->data[byteoff++] |= b >> bitrem;
1971cb0ef41Sopenharmony_ci                else
1981cb0ef41Sopenharmony_ci                    c->data[byteoff++] = b;
1991cb0ef41Sopenharmony_ci                bitoff += (unsigned int)bits;
2001cb0ef41Sopenharmony_ci                if (bitoff == WHIRLPOOL_BBLOCK) {
2011cb0ef41Sopenharmony_ci                    whirlpool_block(c, c->data, 1);
2021cb0ef41Sopenharmony_ci                    byteoff = 0;
2031cb0ef41Sopenharmony_ci                    bitoff %= WHIRLPOOL_BBLOCK;
2041cb0ef41Sopenharmony_ci                }
2051cb0ef41Sopenharmony_ci                if (bitrem)
2061cb0ef41Sopenharmony_ci                    c->data[byteoff] = b << (8 - bitrem);
2071cb0ef41Sopenharmony_ci                bits = 0;
2081cb0ef41Sopenharmony_ci            }
2091cb0ef41Sopenharmony_ci            c->bitoff = bitoff;
2101cb0ef41Sopenharmony_ci        }
2111cb0ef41Sopenharmony_ci    }
2121cb0ef41Sopenharmony_ci}
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ciint WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c)
2151cb0ef41Sopenharmony_ci{
2161cb0ef41Sopenharmony_ci    unsigned int bitoff = c->bitoff, byteoff = bitoff / 8;
2171cb0ef41Sopenharmony_ci    size_t i, j, v;
2181cb0ef41Sopenharmony_ci    unsigned char *p;
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci    bitoff %= 8;
2211cb0ef41Sopenharmony_ci    if (bitoff)
2221cb0ef41Sopenharmony_ci        c->data[byteoff] |= 0x80 >> bitoff;
2231cb0ef41Sopenharmony_ci    else
2241cb0ef41Sopenharmony_ci        c->data[byteoff] = 0x80;
2251cb0ef41Sopenharmony_ci    byteoff++;
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci    /* pad with zeros */
2281cb0ef41Sopenharmony_ci    if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) {
2291cb0ef41Sopenharmony_ci        if (byteoff < WHIRLPOOL_BBLOCK / 8)
2301cb0ef41Sopenharmony_ci            memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff);
2311cb0ef41Sopenharmony_ci        whirlpool_block(c, c->data, 1);
2321cb0ef41Sopenharmony_ci        byteoff = 0;
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci    if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER))
2351cb0ef41Sopenharmony_ci        memset(&c->data[byteoff], 0,
2361cb0ef41Sopenharmony_ci               (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff);
2371cb0ef41Sopenharmony_ci    /* smash 256-bit c->bitlen in big-endian order */
2381cb0ef41Sopenharmony_ci    p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */
2391cb0ef41Sopenharmony_ci    for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++)
2401cb0ef41Sopenharmony_ci        for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8)
2411cb0ef41Sopenharmony_ci            *p-- = (unsigned char)(v & 0xff);
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci    whirlpool_block(c, c->data, 1);
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci    if (md) {
2461cb0ef41Sopenharmony_ci        memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH);
2471cb0ef41Sopenharmony_ci        OPENSSL_cleanse(c, sizeof(*c));
2481cb0ef41Sopenharmony_ci        return 1;
2491cb0ef41Sopenharmony_ci    }
2501cb0ef41Sopenharmony_ci    return 0;
2511cb0ef41Sopenharmony_ci}
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ciunsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md)
2541cb0ef41Sopenharmony_ci{
2551cb0ef41Sopenharmony_ci    WHIRLPOOL_CTX ctx;
2561cb0ef41Sopenharmony_ci    static unsigned char m[WHIRLPOOL_DIGEST_LENGTH];
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci    if (md == NULL)
2591cb0ef41Sopenharmony_ci        md = m;
2601cb0ef41Sopenharmony_ci    WHIRLPOOL_Init(&ctx);
2611cb0ef41Sopenharmony_ci    WHIRLPOOL_Update(&ctx, inp, bytes);
2621cb0ef41Sopenharmony_ci    WHIRLPOOL_Final(md, &ctx);
2631cb0ef41Sopenharmony_ci    return md;
2641cb0ef41Sopenharmony_ci}
265