Path: blob/main/crypto/openssl/providers/implementations/digests/blake2b_prov.c
106622 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 "internal/numbers.h"20#include "blake2_impl.h"21#include "prov/blake2.h"2223static const uint64_t blake2b_IV[8] = {240x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,250x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,260x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,270x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL28};2930static const uint8_t blake2b_sigma[12][16] = {31{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },32{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },33{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },34{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },35{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },36{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },37{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },38{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },39{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },40{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },41{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },42{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }43};4445/* Set that it's the last block we'll compress */46static ossl_inline void blake2b_set_lastblock(BLAKE2B_CTX *S)47{48S->f[0] = -1;49}5051/* Initialize the hashing state. */52static ossl_inline void blake2b_init0(BLAKE2B_CTX *S)53{54int i;5556memset(S, 0, sizeof(BLAKE2B_CTX));57for (i = 0; i < 8; ++i) {58S->h[i] = blake2b_IV[i];59}60}6162/* init xors IV with input parameter block and sets the output length */63static void blake2b_init_param(BLAKE2B_CTX *S, const BLAKE2B_PARAM *P)64{65size_t i;66const uint8_t *p = (const uint8_t *)(P);6768blake2b_init0(S);69S->outlen = P->digest_length;7071/* The param struct is carefully hand packed, and should be 64 bytes on72* every platform. */73assert(sizeof(BLAKE2B_PARAM) == 64);74/* IV XOR ParamBlock */75for (i = 0; i < 8; ++i) {76S->h[i] ^= load64(p + sizeof(S->h[i]) * i);77}78}7980/* Initialize the parameter block with default values */81void ossl_blake2b_param_init(BLAKE2B_PARAM *P)82{83P->digest_length = BLAKE2B_DIGEST_LENGTH;84P->key_length = 0;85P->fanout = 1;86P->depth = 1;87store32(P->leaf_length, 0);88store64(P->node_offset, 0);89P->node_depth = 0;90P->inner_length = 0;91memset(P->reserved, 0, sizeof(P->reserved));92memset(P->salt, 0, sizeof(P->salt));93memset(P->personal, 0, sizeof(P->personal));94}9596void ossl_blake2b_param_set_digest_length(BLAKE2B_PARAM *P, uint8_t outlen)97{98P->digest_length = outlen;99}100101void ossl_blake2b_param_set_key_length(BLAKE2B_PARAM *P, uint8_t keylen)102{103P->key_length = keylen;104}105106void ossl_blake2b_param_set_personal(BLAKE2B_PARAM *P, const uint8_t *personal,107size_t len)108{109memcpy(P->personal, personal, len);110memset(P->personal + len, 0, BLAKE2B_PERSONALBYTES - len);111}112113void ossl_blake2b_param_set_salt(BLAKE2B_PARAM *P, const uint8_t *salt,114size_t len)115{116memcpy(P->salt, salt, len);117memset(P->salt + len, 0, BLAKE2B_SALTBYTES - len);118}119120/*121* Initialize the hashing context with the given parameter block.122* Always returns 1.123*/124int ossl_blake2b_init(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P)125{126blake2b_init_param(c, P);127return 1;128}129130/*131* Initialize the hashing context with the given parameter block and key.132* Always returns 1.133*/134int ossl_blake2b_init_key(BLAKE2B_CTX *c, const BLAKE2B_PARAM *P,135const void *key)136{137blake2b_init_param(c, P);138139/* Pad the key to form first data block */140{141uint8_t block[BLAKE2B_BLOCKBYTES] = { 0 };142143memcpy(block, key, P->key_length);144ossl_blake2b_update(c, block, BLAKE2B_BLOCKBYTES);145OPENSSL_cleanse(block, BLAKE2B_BLOCKBYTES);146}147148return 1;149}150151/* Permute the state while xoring in the block of data. */152static void blake2b_compress(BLAKE2B_CTX *S,153const uint8_t *blocks,154size_t len)155{156uint64_t m[16];157uint64_t v[16];158int i;159size_t increment;160161/*162* There are two distinct usage vectors for this function:163*164* a) BLAKE2b_Update uses it to process complete blocks,165* possibly more than one at a time;166*167* b) BLAK2b_Final uses it to process last block, always168* single but possibly incomplete, in which case caller169* pads input with zeros.170*/171assert(len < BLAKE2B_BLOCKBYTES || len % BLAKE2B_BLOCKBYTES == 0);172173/*174* Since last block is always processed with separate call,175* |len| not being multiple of complete blocks can be observed176* only with |len| being less than BLAKE2B_BLOCKBYTES ("less"177* including even zero), which is why following assignment doesn't178* have to reside inside the main loop below.179*/180increment = len < BLAKE2B_BLOCKBYTES ? len : BLAKE2B_BLOCKBYTES;181182for (i = 0; i < 8; ++i) {183v[i] = S->h[i];184}185186do {187for (i = 0; i < 16; ++i) {188m[i] = load64(blocks + i * sizeof(m[i]));189}190191/* blake2b_increment_counter */192S->t[0] += increment;193S->t[1] += (S->t[0] < increment);194195v[8] = blake2b_IV[0];196v[9] = blake2b_IV[1];197v[10] = blake2b_IV[2];198v[11] = blake2b_IV[3];199v[12] = S->t[0] ^ blake2b_IV[4];200v[13] = S->t[1] ^ blake2b_IV[5];201v[14] = S->f[0] ^ blake2b_IV[6];202v[15] = S->f[1] ^ blake2b_IV[7];203#define G(r, i, a, b, c, d) \204do { \205a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \206d = rotr64(d ^ a, 32); \207c = c + d; \208b = rotr64(b ^ c, 24); \209a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \210d = rotr64(d ^ a, 16); \211c = c + d; \212b = rotr64(b ^ c, 63); \213} while (0)214#define ROUND(r) \215do { \216G(r, 0, v[0], v[4], v[8], v[12]); \217G(r, 1, v[1], v[5], v[9], v[13]); \218G(r, 2, v[2], v[6], v[10], v[14]); \219G(r, 3, v[3], v[7], v[11], v[15]); \220G(r, 4, v[0], v[5], v[10], v[15]); \221G(r, 5, v[1], v[6], v[11], v[12]); \222G(r, 6, v[2], v[7], v[8], v[13]); \223G(r, 7, v[3], v[4], v[9], v[14]); \224} while (0)225#if defined(OPENSSL_SMALL_FOOTPRINT)226/* 3x size reduction on x86_64, almost 7x on ARMv8, 9x on ARMv4 */227for (i = 0; i < 12; i++) {228ROUND(i);229}230#else231ROUND(0);232ROUND(1);233ROUND(2);234ROUND(3);235ROUND(4);236ROUND(5);237ROUND(6);238ROUND(7);239ROUND(8);240ROUND(9);241ROUND(10);242ROUND(11);243#endif244245for (i = 0; i < 8; ++i) {246S->h[i] = v[i] ^= v[i + 8] ^ S->h[i];247}248#undef G249#undef ROUND250blocks += increment;251len -= increment;252} while (len);253}254255/* Absorb the input data into the hash state. Always returns 1. */256int ossl_blake2b_update(BLAKE2B_CTX *c, const void *data, size_t datalen)257{258const uint8_t *in = data;259size_t fill;260261/*262* Intuitively one would expect intermediate buffer, c->buf, to263* store incomplete blocks. But in this case we are interested to264* temporarily stash even complete blocks, because last one in the265* stream has to be treated in special way, and at this point we266* don't know if last block in *this* call is last one "ever". This267* is the reason for why |datalen| is compared as >, and not >=.268*/269fill = sizeof(c->buf) - c->buflen;270if (datalen > fill) {271if (c->buflen) {272memcpy(c->buf + c->buflen, in, fill); /* Fill buffer */273blake2b_compress(c, c->buf, BLAKE2B_BLOCKBYTES);274c->buflen = 0;275in += fill;276datalen -= fill;277}278if (datalen > BLAKE2B_BLOCKBYTES) {279size_t stashlen = datalen % BLAKE2B_BLOCKBYTES;280/*281* If |datalen| is a multiple of the blocksize, stash282* last complete block, it can be final one...283*/284stashlen = stashlen ? stashlen : BLAKE2B_BLOCKBYTES;285datalen -= stashlen;286blake2b_compress(c, in, datalen);287in += datalen;288datalen = stashlen;289}290}291292assert(datalen <= BLAKE2B_BLOCKBYTES);293294memcpy(c->buf + c->buflen, in, datalen);295c->buflen += datalen; /* Be lazy, do not compress */296297return 1;298}299300/*301* Calculate the final hash and save it in md.302* Always returns 1.303*/304int ossl_blake2b_final(unsigned char *md, BLAKE2B_CTX *c)305{306uint8_t outbuffer[BLAKE2B_OUTBYTES] = { 0 };307uint8_t *target = outbuffer;308int iter = (c->outlen + 7) / 8;309int i;310311/* Avoid writing to the temporary buffer if possible */312if ((c->outlen % sizeof(c->h[0])) == 0)313target = md;314315blake2b_set_lastblock(c);316/* Padding */317memset(c->buf + c->buflen, 0, sizeof(c->buf) - c->buflen);318blake2b_compress(c, c->buf, c->buflen);319320/* Output full hash to buffer */321for (i = 0; i < iter; ++i)322store64(target + sizeof(c->h[i]) * i, c->h[i]);323324if (target != md) {325memcpy(md, target, c->outlen);326OPENSSL_cleanse(target, sizeof(outbuffer));327}328329OPENSSL_cleanse(c, sizeof(BLAKE2B_CTX));330return 1;331}332333334