Path: blob/main/crypto/libecc/src/hash/streebog.c
105677 views
/*1* Copyright (C) 2021 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6*7* This software is licensed under a dual BSD and GPL v2 license.8* See LICENSE file at the root folder of the project.9*/10#include <libecc/lib_ecc_config.h>11#if defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)1213/*14* NOTE: we put STREEBOG256 and STREEBOG512 in the same compilation unit on15* purpose, so that we avoid duplicating the rather big tables that are shared16* between the two digest versions.17*/1819#include <libecc/utils/utils.h>20#if defined(WITH_HASH_STREEBOG256)21#include <libecc/hash/streebog256.h>22#endif23#if defined(WITH_HASH_STREEBOG512)24#include <libecc/hash/streebog512.h>25#endif2627/*** Generic functions for both STREEBOG256 and STREEBOG512 ***/28/* Init */29ATTRIBUTE_WARN_UNUSED_RET static int streebog_init(streebog_context *ctx, u8 digest_size, u8 block_size)30{31int ret;3233/* Sanity check */34MUST_HAVE((digest_size == STREEBOG256_DIGEST_SIZE) || (digest_size == STREEBOG512_DIGEST_SIZE), ret, err);3536MUST_HAVE((ctx != NULL), ret, err);3738/* Zeroize the internal state */39ret = local_memset(ctx, 0, sizeof(streebog_context)); EG(ret, err);4041if(digest_size == 32){42ret = local_memset(ctx->h, 1, sizeof(ctx->h)); EG(ret, err);43}4445/* Initialize our digest size and block size */46ctx->streebog_digest_size = digest_size;47ctx->streebog_block_size = block_size;48/* Detect endianness */49ctx->streebog_endian = arch_is_big_endian() ? STREEBOG_BIG : STREEBOG_LITTLE;5051err:52return ret;53}5455ATTRIBUTE_WARN_UNUSED_RET static int streebog_update(streebog_context *ctx, const u8 *input, u32 ilen)56{57const u8 *data_ptr = input;58u32 remain_ilen = ilen;59u16 fill;60u8 left;61int ret;6263MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err);6465/* Nothing to process, return */66if (ilen == 0) {67ret = 0;68goto err;69}7071/* Get what's left in our local buffer */72left = (ctx->streebog_total & 0x3F);73fill = (u16)(STREEBOG_BLOCK_SIZE - left);7475ctx->streebog_total += ilen;7677if ((left > 0) && (remain_ilen >= fill)) {78/* Copy data at the end of the buffer */79ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, fill); EG(ret, err);80streebog_process(ctx, ctx->streebog_buffer, (8 * STREEBOG_BLOCK_SIZE));81data_ptr += fill;82remain_ilen -= fill;83left = 0;84}8586while (remain_ilen >= STREEBOG_BLOCK_SIZE) {87streebog_process(ctx, data_ptr, (8 * STREEBOG_BLOCK_SIZE));88data_ptr += STREEBOG_BLOCK_SIZE;89remain_ilen -= STREEBOG_BLOCK_SIZE;90}9192if (remain_ilen > 0) {93ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, remain_ilen); EG(ret, err);94}9596ret = 0;9798err:99return ret;100}101102ATTRIBUTE_WARN_UNUSED_RET static int streebog_final(streebog_context *ctx, u8 *output)103{104unsigned int block_present = 0;105u8 last_padded_block[STREEBOG_BLOCK_SIZE];106u64 Z[STREEBOG_BLOCK_U64_SIZE];107unsigned int j;108u8 digest_size;109u8 idx;110int ret;111112MUST_HAVE((ctx != NULL) && (output != NULL), ret, err);113114digest_size = ctx->streebog_digest_size;115/* Sanity check */116MUST_HAVE((digest_size == 32) || (digest_size == 64), ret, err);117118/* Zero init our Z */119ret = local_memset(Z, 0, sizeof(Z)); EG(ret, err);120121/* Fill in our last block with zeroes */122ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);123124/* This is our final step, so we proceed with the padding */125block_present = (ctx->streebog_total % STREEBOG_BLOCK_SIZE);126if (block_present != 0) {127/* Copy what's left in our temporary context buffer */128ret = local_memcpy(last_padded_block, ctx->streebog_buffer,129block_present); EG(ret, err);130}131132/* Put the 0x01 byte, beginning of padding */133last_padded_block[block_present] = 0x01;134135streebog_process(ctx, last_padded_block, (8 * (ctx->streebog_total % STREEBOG_BLOCK_SIZE)));136137gN(ctx->h, ctx->N, Z);138gN(ctx->h, ctx->Sigma, Z);139140for(j = 0; j < STREEBOG_BLOCK_U64_SIZE; j++){141ctx->h[j] = S64(ctx->h[j]);142}143144idx = 0;145146if(digest_size == 64){147/* 512-bit hash case */148STREEBOG_PUT_UINT64(ctx->h[0], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);149STREEBOG_PUT_UINT64(ctx->h[1], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);150STREEBOG_PUT_UINT64(ctx->h[2], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);151STREEBOG_PUT_UINT64(ctx->h[3], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);152}153/* 256 and 512-bit hash case */154STREEBOG_PUT_UINT64(ctx->h[4], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);155STREEBOG_PUT_UINT64(ctx->h[5], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);156STREEBOG_PUT_UINT64(ctx->h[6], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);157STREEBOG_PUT_UINT64(ctx->h[7], output, idx, ctx->streebog_endian);158159ret = 0;160161err:162return ret;163}164165#if defined(WITH_HASH_STREEBOG256)166167/* Init */168int streebog256_init(streebog256_context *ctx)169{170int ret;171172ret = streebog_init(ctx, STREEBOG256_DIGEST_SIZE, STREEBOG256_BLOCK_SIZE); EG(ret, err);173174ctx->magic = STREEBOG256_HASH_MAGIC;175176err:177return ret;178}179180/* Update */181int streebog256_update(streebog256_context *ctx, const u8 *input, u32 ilen)182{183int ret;184185STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err);186187ret = streebog_update(ctx, input, ilen);188189err:190return ret;191}192193/* Finalize */194int streebog256_final(streebog256_context *ctx,195u8 output[STREEBOG256_DIGEST_SIZE])196{197int ret;198199STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err);200201ret = streebog_final(ctx, output); EG(ret, err);202203/* Uninit our context magic */204ctx->magic = WORD(0);205206ret = 0;207208err:209return ret;210}211212int streebog256_scattered(const u8 **inputs, const u32 *ilens,213u8 output[STREEBOG256_DIGEST_SIZE])214{215streebog256_context ctx;216int pos = 0;217int ret;218219MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);220221ret = streebog256_init(&ctx); EG(ret, err);222223while (inputs[pos] != NULL) {224ret = streebog256_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);225pos += 1;226}227228ret = streebog256_final(&ctx, output);229230err:231return ret;232}233234int streebog256(const u8 *input, u32 ilen, u8 output[STREEBOG256_DIGEST_SIZE])235{236int ret;237streebog256_context ctx;238239ret = streebog256_init(&ctx); EG(ret, err);240ret = streebog256_update(&ctx, input, ilen); EG(ret, err);241ret = streebog256_final(&ctx, output);242243err:244return ret;245}246247#endif /* defined(WITH_HASH_STREEBOG256) */248249250#if defined(WITH_HASH_STREEBOG512)251252/* Init */253int streebog512_init(streebog512_context *ctx)254{255int ret;256257ret = streebog_init(ctx, STREEBOG512_DIGEST_SIZE, STREEBOG512_BLOCK_SIZE); EG(ret, err);258259ctx->magic = STREEBOG512_HASH_MAGIC;260261ret = 0;262263err:264return ret;265}266267/* Update */268int streebog512_update(streebog512_context *ctx, const u8 *input, u32 ilen)269{270int ret;271272STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err);273274ret = streebog_update(ctx, input, ilen);275276err:277return ret;278}279280/* Finalize */281int streebog512_final(streebog512_context *ctx,282u8 output[STREEBOG512_DIGEST_SIZE])283{284int ret;285286STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err);287288ret = streebog_final(ctx, output); EG(ret, err);289290/* Uninit our context magic */291ctx->magic = WORD(0);292293ret = 0;294295err:296return ret;297}298299int streebog512_scattered(const u8 **inputs, const u32 *ilens,300u8 output[STREEBOG512_DIGEST_SIZE])301{302streebog512_context ctx;303int pos = 0;304int ret;305306MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);307308ret = streebog512_init(&ctx); EG(ret, err);309310while (inputs[pos] != NULL) {311ret = streebog512_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);312pos += 1;313}314315ret = streebog512_final(&ctx, output);316317err:318return ret;319}320321int streebog512(const u8 *input, u32 ilen, u8 output[STREEBOG512_DIGEST_SIZE])322{323int ret;324streebog512_context ctx;325326ret = streebog512_init(&ctx); EG(ret, err);327ret = streebog512_update(&ctx, input, ilen); EG(ret, err);328ret = streebog512_final(&ctx, output);329330err:331return ret;332}333334#endif /* defined(WITH_HASH_STREEBOG512) */335336#else /* !(defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)) */337/*338* Dummy definition to avoid the empty translation unit ISO C warning339*/340typedef int dummy;341342#endif /* defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512) */343344345346