Path: blob/main/crypto/openssl/providers/implementations/digests/blake2s_prov.c
107173 views
/*1* Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* Derived from the BLAKE2 reference implementation written by Samuel Neves.11* Copyright 2012, Samuel Neves <[email protected]>12* More information about the BLAKE2 hash function and its implementations13* can be found at https://blake2.net.14*/1516#include <assert.h>17#include <string.h>18#include <openssl/crypto.h>19#include "blake2_impl.h"20#include "prov/blake2.h"2122static const uint32_t blake2s_IV[8] = {230x6A09E667U, 0xBB67AE85U, 0x3C6EF372U, 0xA54FF53AU,240x510E527FU, 0x9B05688CU, 0x1F83D9ABU, 0x5BE0CD19U25};2627static const uint8_t blake2s_sigma[10][16] = {28{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },29{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },30{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },31{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },32{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },33{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },34{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },35{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },36{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },37{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },38};3940/* Set that it's the last block we'll compress */41static ossl_inline void blake2s_set_lastblock(BLAKE2S_CTX *S)42{43S->f[0] = -1;44}4546/* Initialize the hashing state. */47static ossl_inline void blake2s_init0(BLAKE2S_CTX *S)48{49int i;5051memset(S, 0, sizeof(BLAKE2S_CTX));52for (i = 0; i < 8; ++i) {53S->h[i] = blake2s_IV[i];54}55}5657/* init xors IV with input parameter block and sets the output length */58static void blake2s_init_param(BLAKE2S_CTX *S, const BLAKE2S_PARAM *P)59{60size_t i;61const uint8_t *p = (const uint8_t *)(P);6263blake2s_init0(S);64S->outlen = P->digest_length;6566/* The param struct is carefully hand packed, and should be 32 bytes on67* every platform. */68assert(sizeof(BLAKE2S_PARAM) == 32);69/* IV XOR ParamBlock */70for (i = 0; i < 8; ++i) {71S->h[i] ^= load32(&p[i * 4]);72}73}7475void ossl_blake2s_param_init(BLAKE2S_PARAM *P)76{77P->digest_length = BLAKE2S_DIGEST_LENGTH;78P->key_length = 0;79P->fanout = 1;80P->depth = 1;81store32(P->leaf_length, 0);82store48(P->node_offset, 0);83P->node_depth = 0;84P->inner_length = 0;85memset(P->salt, 0, sizeof(P->salt));86memset(P->personal, 0, sizeof(P->personal));87}8889void ossl_blake2s_param_set_digest_length(BLAKE2S_PARAM *P, uint8_t outlen)90{91P->digest_length = outlen;92}9394void ossl_blake2s_param_set_key_length(BLAKE2S_PARAM *P, uint8_t keylen)95{96P->key_length = keylen;97}9899void ossl_blake2s_param_set_personal(BLAKE2S_PARAM *P, const uint8_t *personal,100size_t len)101{102memcpy(P->personal, personal, len);103memset(P->personal + len, 0, BLAKE2S_PERSONALBYTES - len);104}105106void ossl_blake2s_param_set_salt(BLAKE2S_PARAM *P, const uint8_t *salt,107size_t len)108{109memcpy(P->salt, salt, len);110memset(P->salt + len, 0, BLAKE2S_SALTBYTES - len);111}112113/*114* Initialize the hashing context with the given parameter block.115* Always returns 1.116*/117int ossl_blake2s_init(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P)118{119blake2s_init_param(c, P);120return 1;121}122123/*124* Initialize the hashing context with the given parameter block and key.125* Always returns 1.126*/127int ossl_blake2s_init_key(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P,128const void *key)129{130blake2s_init_param(c, P);131132/* Pad the key to form first data block */133{134uint8_t block[BLAKE2S_BLOCKBYTES] = { 0 };135136memcpy(block, key, P->key_length);137ossl_blake2s_update(c, block, BLAKE2S_BLOCKBYTES);138OPENSSL_cleanse(block, BLAKE2S_BLOCKBYTES);139}140141return 1;142}143144/* Permute the state while xoring in the block of data. */145static void blake2s_compress(BLAKE2S_CTX *S,146const uint8_t *blocks,147size_t len)148{149uint32_t m[16];150uint32_t v[16];151size_t i;152size_t increment;153154/*155* There are two distinct usage vectors for this function:156*157* a) BLAKE2s_Update uses it to process complete blocks,158* possibly more than one at a time;159*160* b) BLAK2s_Final uses it to process last block, always161* single but possibly incomplete, in which case caller162* pads input with zeros.163*/164assert(len < BLAKE2S_BLOCKBYTES || len % BLAKE2S_BLOCKBYTES == 0);165166/*167* Since last block is always processed with separate call,168* |len| not being multiple of complete blocks can be observed169* only with |len| being less than BLAKE2S_BLOCKBYTES ("less"170* including even zero), which is why following assignment doesn't171* have to reside inside the main loop below.172*/173increment = len < BLAKE2S_BLOCKBYTES ? len : BLAKE2S_BLOCKBYTES;174175for (i = 0; i < 8; ++i) {176v[i] = S->h[i];177}178179do {180for (i = 0; i < 16; ++i) {181m[i] = load32(blocks + i * sizeof(m[i]));182}183184/* blake2s_increment_counter */185S->t[0] += increment;186S->t[1] += (S->t[0] < increment);187188v[8] = blake2s_IV[0];189v[9] = blake2s_IV[1];190v[10] = blake2s_IV[2];191v[11] = blake2s_IV[3];192v[12] = S->t[0] ^ blake2s_IV[4];193v[13] = S->t[1] ^ blake2s_IV[5];194v[14] = S->f[0] ^ blake2s_IV[6];195v[15] = S->f[1] ^ blake2s_IV[7];196#define G(r, i, a, b, c, d) \197do { \198a = a + b + m[blake2s_sigma[r][2 * i + 0]]; \199d = rotr32(d ^ a, 16); \200c = c + d; \201b = rotr32(b ^ c, 12); \202a = a + b + m[blake2s_sigma[r][2 * i + 1]]; \203d = rotr32(d ^ a, 8); \204c = c + d; \205b = rotr32(b ^ c, 7); \206} while (0)207#define ROUND(r) \208do { \209G(r, 0, v[0], v[4], v[8], v[12]); \210G(r, 1, v[1], v[5], v[9], v[13]); \211G(r, 2, v[2], v[6], v[10], v[14]); \212G(r, 3, v[3], v[7], v[11], v[15]); \213G(r, 4, v[0], v[5], v[10], v[15]); \214G(r, 5, v[1], v[6], v[11], v[12]); \215G(r, 6, v[2], v[7], v[8], v[13]); \216G(r, 7, v[3], v[4], v[9], v[14]); \217} while (0)218#if defined(OPENSSL_SMALL_FOOTPRINT)219/* almost 3x reduction on x86_64, 4.5x on ARMv8, 4x on ARMv4 */220for (i = 0; i < 10; i++) {221ROUND(i);222}223#else224ROUND(0);225ROUND(1);226ROUND(2);227ROUND(3);228ROUND(4);229ROUND(5);230ROUND(6);231ROUND(7);232ROUND(8);233ROUND(9);234#endif235236for (i = 0; i < 8; ++i) {237S->h[i] = v[i] ^= v[i + 8] ^ S->h[i];238}239#undef G240#undef ROUND241blocks += increment;242len -= increment;243} while (len);244}245246/* Absorb the input data into the hash state. Always returns 1. */247int ossl_blake2s_update(BLAKE2S_CTX *c, const void *data, size_t datalen)248{249const uint8_t *in = data;250size_t fill;251252/*253* Intuitively one would expect intermediate buffer, c->buf, to254* store incomplete blocks. But in this case we are interested to255* temporarily stash even complete blocks, because last one in the256* stream has to be treated in special way, and at this point we257* don't know if last block in *this* call is last one "ever". This258* is the reason for why |datalen| is compared as >, and not >=.259*/260fill = sizeof(c->buf) - c->buflen;261if (datalen > fill) {262if (c->buflen) {263memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */264blake2s_compress(c, c->buf, BLAKE2S_BLOCKBYTES);265c->buflen = 0;266in += fill;267datalen -= fill;268}269if (datalen > BLAKE2S_BLOCKBYTES) {270size_t stashlen = datalen % BLAKE2S_BLOCKBYTES;271/*272* If |datalen| is a multiple of the blocksize, stash273* last complete block, it can be final one...274*/275stashlen = stashlen ? stashlen : BLAKE2S_BLOCKBYTES;276datalen -= stashlen;277blake2s_compress(c, in, datalen);278in += datalen;279datalen = stashlen;280}281}282283assert(datalen <= BLAKE2S_BLOCKBYTES);284285memcpy(c->buf + c->buflen, in, datalen);286c->buflen += datalen; /* Be lazy, do not compress */287288return 1;289}290291/*292* Calculate the final hash and save it in md.293* Always returns 1.294*/295int ossl_blake2s_final(unsigned char *md, BLAKE2S_CTX *c)296{297uint8_t outbuffer[BLAKE2S_OUTBYTES] = { 0 };298uint8_t *target = outbuffer;299int iter = (c->outlen + 3) / 4;300int i;301302/* Avoid writing to the temporary buffer if possible */303if ((c->outlen % sizeof(c->h[0])) == 0)304target = md;305306blake2s_set_lastblock(c);307/* Padding */308memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen);309blake2s_compress(c, c->buf, c->buflen);310311/* Output full hash to buffer */312for (i = 0; i < iter; ++i)313store32(target + sizeof(c->h[i]) * i, c->h[i]);314315if (target != md) {316memcpy(md, target, c->outlen);317OPENSSL_cleanse(target, sizeof(outbuffer));318}319320OPENSSL_cleanse(c, sizeof(BLAKE2S_CTX));321return 1;322}323324325