Path: blob/main/crypto/openssl/providers/implementations/digests/blake2s_prov.c
48383 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);}111112/*113* Initialize the hashing context with the given parameter block.114* Always returns 1.115*/116int ossl_blake2s_init(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P)117{118blake2s_init_param(c, P);119return 1;120}121122/*123* Initialize the hashing context with the given parameter block and key.124* Always returns 1.125*/126int ossl_blake2s_init_key(BLAKE2S_CTX *c, const BLAKE2S_PARAM *P,127const void *key)128{129blake2s_init_param(c, P);130131/* Pad the key to form first data block */132{133uint8_t block[BLAKE2S_BLOCKBYTES] = {0};134135memcpy(block, key, P->key_length);136ossl_blake2s_update(c, block, BLAKE2S_BLOCKBYTES);137OPENSSL_cleanse(block, BLAKE2S_BLOCKBYTES);138}139140return 1;141}142143/* Permute the state while xoring in the block of data. */144static void blake2s_compress(BLAKE2S_CTX *S,145const uint8_t *blocks,146size_t len)147{148uint32_t m[16];149uint32_t v[16];150size_t i;151size_t increment;152153/*154* There are two distinct usage vectors for this function:155*156* a) BLAKE2s_Update uses it to process complete blocks,157* possibly more than one at a time;158*159* b) BLAK2s_Final uses it to process last block, always160* single but possibly incomplete, in which case caller161* pads input with zeros.162*/163assert(len < BLAKE2S_BLOCKBYTES || len % BLAKE2S_BLOCKBYTES == 0);164165/*166* Since last block is always processed with separate call,167* |len| not being multiple of complete blocks can be observed168* only with |len| being less than BLAKE2S_BLOCKBYTES ("less"169* including even zero), which is why following assignment doesn't170* have to reside inside the main loop below.171*/172increment = len < BLAKE2S_BLOCKBYTES ? len : BLAKE2S_BLOCKBYTES;173174for (i = 0; i < 8; ++i) {175v[i] = S->h[i];176}177178do {179for (i = 0; i < 16; ++i) {180m[i] = load32(blocks + i * sizeof(m[i]));181}182183/* blake2s_increment_counter */184S->t[0] += increment;185S->t[1] += (S->t[0] < increment);186187v[ 8] = blake2s_IV[0];188v[ 9] = blake2s_IV[1];189v[10] = blake2s_IV[2];190v[11] = blake2s_IV[3];191v[12] = S->t[0] ^ blake2s_IV[4];192v[13] = S->t[1] ^ blake2s_IV[5];193v[14] = S->f[0] ^ blake2s_IV[6];194v[15] = S->f[1] ^ blake2s_IV[7];195#define G(r,i,a,b,c,d) \196do { \197a = a + b + m[blake2s_sigma[r][2*i+0]]; \198d = rotr32(d ^ a, 16); \199c = c + d; \200b = rotr32(b ^ c, 12); \201a = a + b + m[blake2s_sigma[r][2*i+1]]; \202d = rotr32(d ^ a, 8); \203c = c + d; \204b = rotr32(b ^ c, 7); \205} while (0)206#define ROUND(r) \207do { \208G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \209G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \210G(r,2,v[ 2],v[ 6],v[10],v[14]); \211G(r,3,v[ 3],v[ 7],v[11],v[15]); \212G(r,4,v[ 0],v[ 5],v[10],v[15]); \213G(r,5,v[ 1],v[ 6],v[11],v[12]); \214G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \215G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \216} while (0)217#if defined(OPENSSL_SMALL_FOOTPRINT)218/* almost 3x reduction on x86_64, 4.5x on ARMv8, 4x on ARMv4 */219for (i = 0; i < 10; i++) {220ROUND(i);221}222#else223ROUND(0);224ROUND(1);225ROUND(2);226ROUND(3);227ROUND(4);228ROUND(5);229ROUND(6);230ROUND(7);231ROUND(8);232ROUND(9);233#endif234235for (i = 0; i < 8; ++i) {236S->h[i] = v[i] ^= v[i + 8] ^ S->h[i];237}238#undef G239#undef ROUND240blocks += increment;241len -= increment;242} while (len);243}244245/* Absorb the input data into the hash state. Always returns 1. */246int ossl_blake2s_update(BLAKE2S_CTX *c, const void *data, size_t datalen)247{248const uint8_t *in = data;249size_t fill;250251/*252* Intuitively one would expect intermediate buffer, c->buf, to253* store incomplete blocks. But in this case we are interested to254* temporarily stash even complete blocks, because last one in the255* stream has to be treated in special way, and at this point we256* don't know if last block in *this* call is last one "ever". This257* is the reason for why |datalen| is compared as >, and not >=.258*/259fill = sizeof(c->buf) - c->buflen;260if (datalen > fill) {261if (c->buflen) {262memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */263blake2s_compress(c, c->buf, BLAKE2S_BLOCKBYTES);264c->buflen = 0;265in += fill;266datalen -= fill;267}268if (datalen > BLAKE2S_BLOCKBYTES) {269size_t stashlen = datalen % BLAKE2S_BLOCKBYTES;270/*271* If |datalen| is a multiple of the blocksize, stash272* last complete block, it can be final one...273*/274stashlen = stashlen ? stashlen : BLAKE2S_BLOCKBYTES;275datalen -= stashlen;276blake2s_compress(c, in, datalen);277in += datalen;278datalen = stashlen;279}280}281282assert(datalen <= BLAKE2S_BLOCKBYTES);283284memcpy(c->buf + c->buflen, in, datalen);285c->buflen += datalen; /* Be lazy, do not compress */286287return 1;288}289290/*291* Calculate the final hash and save it in md.292* Always returns 1.293*/294int ossl_blake2s_final(unsigned char *md, BLAKE2S_CTX *c)295{296uint8_t outbuffer[BLAKE2S_OUTBYTES] = {0};297uint8_t *target = outbuffer;298int iter = (c->outlen + 3) / 4;299int i;300301/* Avoid writing to the temporary buffer if possible */302if ((c->outlen % sizeof(c->h[0])) == 0)303target = md;304305blake2s_set_lastblock(c);306/* Padding */307memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen);308blake2s_compress(c, c->buf, c->buflen);309310/* Output full hash to buffer */311for (i = 0; i < iter; ++i)312store32(target + sizeof(c->h[i]) * i, c->h[i]);313314if (target != md) {315memcpy(md, target, c->outlen);316OPENSSL_cleanse(target, sizeof(outbuffer));317}318319OPENSSL_cleanse(c, sizeof(BLAKE2S_CTX));320return 1;321}322323324