1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans * Copyright (C) 2021 - This file is part of libecc project
3*f0865ec9SKyle Evans *
4*f0865ec9SKyle Evans * Authors:
5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans *
8*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license.
9*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project.
10*f0865ec9SKyle Evans */
11*f0865ec9SKyle Evans #include <libecc/lib_ecc_config.h>
12*f0865ec9SKyle Evans #if defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)
13*f0865ec9SKyle Evans
14*f0865ec9SKyle Evans /*
15*f0865ec9SKyle Evans * NOTE: we put STREEBOG256 and STREEBOG512 in the same compilation unit on
16*f0865ec9SKyle Evans * purpose, so that we avoid duplicating the rather big tables that are shared
17*f0865ec9SKyle Evans * between the two digest versions.
18*f0865ec9SKyle Evans */
19*f0865ec9SKyle Evans
20*f0865ec9SKyle Evans #include <libecc/utils/utils.h>
21*f0865ec9SKyle Evans #if defined(WITH_HASH_STREEBOG256)
22*f0865ec9SKyle Evans #include <libecc/hash/streebog256.h>
23*f0865ec9SKyle Evans #endif
24*f0865ec9SKyle Evans #if defined(WITH_HASH_STREEBOG512)
25*f0865ec9SKyle Evans #include <libecc/hash/streebog512.h>
26*f0865ec9SKyle Evans #endif
27*f0865ec9SKyle Evans
28*f0865ec9SKyle Evans /*** Generic functions for both STREEBOG256 and STREEBOG512 ***/
29*f0865ec9SKyle Evans /* Init */
streebog_init(streebog_context * ctx,u8 digest_size,u8 block_size)30*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int streebog_init(streebog_context *ctx, u8 digest_size, u8 block_size)
31*f0865ec9SKyle Evans {
32*f0865ec9SKyle Evans int ret;
33*f0865ec9SKyle Evans
34*f0865ec9SKyle Evans /* Sanity check */
35*f0865ec9SKyle Evans MUST_HAVE((digest_size == STREEBOG256_DIGEST_SIZE) || (digest_size == STREEBOG512_DIGEST_SIZE), ret, err);
36*f0865ec9SKyle Evans
37*f0865ec9SKyle Evans MUST_HAVE((ctx != NULL), ret, err);
38*f0865ec9SKyle Evans
39*f0865ec9SKyle Evans /* Zeroize the internal state */
40*f0865ec9SKyle Evans ret = local_memset(ctx, 0, sizeof(streebog_context)); EG(ret, err);
41*f0865ec9SKyle Evans
42*f0865ec9SKyle Evans if(digest_size == 32){
43*f0865ec9SKyle Evans ret = local_memset(ctx->h, 1, sizeof(ctx->h)); EG(ret, err);
44*f0865ec9SKyle Evans }
45*f0865ec9SKyle Evans
46*f0865ec9SKyle Evans /* Initialize our digest size and block size */
47*f0865ec9SKyle Evans ctx->streebog_digest_size = digest_size;
48*f0865ec9SKyle Evans ctx->streebog_block_size = block_size;
49*f0865ec9SKyle Evans /* Detect endianness */
50*f0865ec9SKyle Evans ctx->streebog_endian = arch_is_big_endian() ? STREEBOG_BIG : STREEBOG_LITTLE;
51*f0865ec9SKyle Evans
52*f0865ec9SKyle Evans err:
53*f0865ec9SKyle Evans return ret;
54*f0865ec9SKyle Evans }
55*f0865ec9SKyle Evans
streebog_update(streebog_context * ctx,const u8 * input,u32 ilen)56*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int streebog_update(streebog_context *ctx, const u8 *input, u32 ilen)
57*f0865ec9SKyle Evans {
58*f0865ec9SKyle Evans const u8 *data_ptr = input;
59*f0865ec9SKyle Evans u32 remain_ilen = ilen;
60*f0865ec9SKyle Evans u16 fill;
61*f0865ec9SKyle Evans u8 left;
62*f0865ec9SKyle Evans int ret;
63*f0865ec9SKyle Evans
64*f0865ec9SKyle Evans MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err);
65*f0865ec9SKyle Evans
66*f0865ec9SKyle Evans /* Nothing to process, return */
67*f0865ec9SKyle Evans if (ilen == 0) {
68*f0865ec9SKyle Evans ret = 0;
69*f0865ec9SKyle Evans goto err;
70*f0865ec9SKyle Evans }
71*f0865ec9SKyle Evans
72*f0865ec9SKyle Evans /* Get what's left in our local buffer */
73*f0865ec9SKyle Evans left = (ctx->streebog_total & 0x3F);
74*f0865ec9SKyle Evans fill = (u16)(STREEBOG_BLOCK_SIZE - left);
75*f0865ec9SKyle Evans
76*f0865ec9SKyle Evans ctx->streebog_total += ilen;
77*f0865ec9SKyle Evans
78*f0865ec9SKyle Evans if ((left > 0) && (remain_ilen >= fill)) {
79*f0865ec9SKyle Evans /* Copy data at the end of the buffer */
80*f0865ec9SKyle Evans ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, fill); EG(ret, err);
81*f0865ec9SKyle Evans streebog_process(ctx, ctx->streebog_buffer, (8 * STREEBOG_BLOCK_SIZE));
82*f0865ec9SKyle Evans data_ptr += fill;
83*f0865ec9SKyle Evans remain_ilen -= fill;
84*f0865ec9SKyle Evans left = 0;
85*f0865ec9SKyle Evans }
86*f0865ec9SKyle Evans
87*f0865ec9SKyle Evans while (remain_ilen >= STREEBOG_BLOCK_SIZE) {
88*f0865ec9SKyle Evans streebog_process(ctx, data_ptr, (8 * STREEBOG_BLOCK_SIZE));
89*f0865ec9SKyle Evans data_ptr += STREEBOG_BLOCK_SIZE;
90*f0865ec9SKyle Evans remain_ilen -= STREEBOG_BLOCK_SIZE;
91*f0865ec9SKyle Evans }
92*f0865ec9SKyle Evans
93*f0865ec9SKyle Evans if (remain_ilen > 0) {
94*f0865ec9SKyle Evans ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, remain_ilen); EG(ret, err);
95*f0865ec9SKyle Evans }
96*f0865ec9SKyle Evans
97*f0865ec9SKyle Evans ret = 0;
98*f0865ec9SKyle Evans
99*f0865ec9SKyle Evans err:
100*f0865ec9SKyle Evans return ret;
101*f0865ec9SKyle Evans }
102*f0865ec9SKyle Evans
streebog_final(streebog_context * ctx,u8 * output)103*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int streebog_final(streebog_context *ctx, u8 *output)
104*f0865ec9SKyle Evans {
105*f0865ec9SKyle Evans unsigned int block_present = 0;
106*f0865ec9SKyle Evans u8 last_padded_block[STREEBOG_BLOCK_SIZE];
107*f0865ec9SKyle Evans u64 Z[STREEBOG_BLOCK_U64_SIZE];
108*f0865ec9SKyle Evans unsigned int j;
109*f0865ec9SKyle Evans u8 digest_size;
110*f0865ec9SKyle Evans u8 idx;
111*f0865ec9SKyle Evans int ret;
112*f0865ec9SKyle Evans
113*f0865ec9SKyle Evans MUST_HAVE((ctx != NULL) && (output != NULL), ret, err);
114*f0865ec9SKyle Evans
115*f0865ec9SKyle Evans digest_size = ctx->streebog_digest_size;
116*f0865ec9SKyle Evans /* Sanity check */
117*f0865ec9SKyle Evans MUST_HAVE((digest_size == 32) || (digest_size == 64), ret, err);
118*f0865ec9SKyle Evans
119*f0865ec9SKyle Evans /* Zero init our Z */
120*f0865ec9SKyle Evans ret = local_memset(Z, 0, sizeof(Z)); EG(ret, err);
121*f0865ec9SKyle Evans
122*f0865ec9SKyle Evans /* Fill in our last block with zeroes */
123*f0865ec9SKyle Evans ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
124*f0865ec9SKyle Evans
125*f0865ec9SKyle Evans /* This is our final step, so we proceed with the padding */
126*f0865ec9SKyle Evans block_present = (ctx->streebog_total % STREEBOG_BLOCK_SIZE);
127*f0865ec9SKyle Evans if (block_present != 0) {
128*f0865ec9SKyle Evans /* Copy what's left in our temporary context buffer */
129*f0865ec9SKyle Evans ret = local_memcpy(last_padded_block, ctx->streebog_buffer,
130*f0865ec9SKyle Evans block_present); EG(ret, err);
131*f0865ec9SKyle Evans }
132*f0865ec9SKyle Evans
133*f0865ec9SKyle Evans /* Put the 0x01 byte, beginning of padding */
134*f0865ec9SKyle Evans last_padded_block[block_present] = 0x01;
135*f0865ec9SKyle Evans
136*f0865ec9SKyle Evans streebog_process(ctx, last_padded_block, (8 * (ctx->streebog_total % STREEBOG_BLOCK_SIZE)));
137*f0865ec9SKyle Evans
138*f0865ec9SKyle Evans gN(ctx->h, ctx->N, Z);
139*f0865ec9SKyle Evans gN(ctx->h, ctx->Sigma, Z);
140*f0865ec9SKyle Evans
141*f0865ec9SKyle Evans for(j = 0; j < STREEBOG_BLOCK_U64_SIZE; j++){
142*f0865ec9SKyle Evans ctx->h[j] = S64(ctx->h[j]);
143*f0865ec9SKyle Evans }
144*f0865ec9SKyle Evans
145*f0865ec9SKyle Evans idx = 0;
146*f0865ec9SKyle Evans
147*f0865ec9SKyle Evans if(digest_size == 64){
148*f0865ec9SKyle Evans /* 512-bit hash case */
149*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[0], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
150*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[1], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
151*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[2], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
152*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[3], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
153*f0865ec9SKyle Evans }
154*f0865ec9SKyle Evans /* 256 and 512-bit hash case */
155*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[4], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
156*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[5], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
157*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[6], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
158*f0865ec9SKyle Evans STREEBOG_PUT_UINT64(ctx->h[7], output, idx, ctx->streebog_endian);
159*f0865ec9SKyle Evans
160*f0865ec9SKyle Evans ret = 0;
161*f0865ec9SKyle Evans
162*f0865ec9SKyle Evans err:
163*f0865ec9SKyle Evans return ret;
164*f0865ec9SKyle Evans }
165*f0865ec9SKyle Evans
166*f0865ec9SKyle Evans #if defined(WITH_HASH_STREEBOG256)
167*f0865ec9SKyle Evans
168*f0865ec9SKyle Evans /* Init */
streebog256_init(streebog256_context * ctx)169*f0865ec9SKyle Evans int streebog256_init(streebog256_context *ctx)
170*f0865ec9SKyle Evans {
171*f0865ec9SKyle Evans int ret;
172*f0865ec9SKyle Evans
173*f0865ec9SKyle Evans ret = streebog_init(ctx, STREEBOG256_DIGEST_SIZE, STREEBOG256_BLOCK_SIZE); EG(ret, err);
174*f0865ec9SKyle Evans
175*f0865ec9SKyle Evans ctx->magic = STREEBOG256_HASH_MAGIC;
176*f0865ec9SKyle Evans
177*f0865ec9SKyle Evans err:
178*f0865ec9SKyle Evans return ret;
179*f0865ec9SKyle Evans }
180*f0865ec9SKyle Evans
181*f0865ec9SKyle Evans /* Update */
streebog256_update(streebog256_context * ctx,const u8 * input,u32 ilen)182*f0865ec9SKyle Evans int streebog256_update(streebog256_context *ctx, const u8 *input, u32 ilen)
183*f0865ec9SKyle Evans {
184*f0865ec9SKyle Evans int ret;
185*f0865ec9SKyle Evans
186*f0865ec9SKyle Evans STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err);
187*f0865ec9SKyle Evans
188*f0865ec9SKyle Evans ret = streebog_update(ctx, input, ilen);
189*f0865ec9SKyle Evans
190*f0865ec9SKyle Evans err:
191*f0865ec9SKyle Evans return ret;
192*f0865ec9SKyle Evans }
193*f0865ec9SKyle Evans
194*f0865ec9SKyle Evans /* Finalize */
streebog256_final(streebog256_context * ctx,u8 output[STREEBOG256_DIGEST_SIZE])195*f0865ec9SKyle Evans int streebog256_final(streebog256_context *ctx,
196*f0865ec9SKyle Evans u8 output[STREEBOG256_DIGEST_SIZE])
197*f0865ec9SKyle Evans {
198*f0865ec9SKyle Evans int ret;
199*f0865ec9SKyle Evans
200*f0865ec9SKyle Evans STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err);
201*f0865ec9SKyle Evans
202*f0865ec9SKyle Evans ret = streebog_final(ctx, output); EG(ret, err);
203*f0865ec9SKyle Evans
204*f0865ec9SKyle Evans /* Uninit our context magic */
205*f0865ec9SKyle Evans ctx->magic = WORD(0);
206*f0865ec9SKyle Evans
207*f0865ec9SKyle Evans ret = 0;
208*f0865ec9SKyle Evans
209*f0865ec9SKyle Evans err:
210*f0865ec9SKyle Evans return ret;
211*f0865ec9SKyle Evans }
212*f0865ec9SKyle Evans
streebog256_scattered(const u8 ** inputs,const u32 * ilens,u8 output[STREEBOG256_DIGEST_SIZE])213*f0865ec9SKyle Evans int streebog256_scattered(const u8 **inputs, const u32 *ilens,
214*f0865ec9SKyle Evans u8 output[STREEBOG256_DIGEST_SIZE])
215*f0865ec9SKyle Evans {
216*f0865ec9SKyle Evans streebog256_context ctx;
217*f0865ec9SKyle Evans int pos = 0;
218*f0865ec9SKyle Evans int ret;
219*f0865ec9SKyle Evans
220*f0865ec9SKyle Evans MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
221*f0865ec9SKyle Evans
222*f0865ec9SKyle Evans ret = streebog256_init(&ctx); EG(ret, err);
223*f0865ec9SKyle Evans
224*f0865ec9SKyle Evans while (inputs[pos] != NULL) {
225*f0865ec9SKyle Evans ret = streebog256_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
226*f0865ec9SKyle Evans pos += 1;
227*f0865ec9SKyle Evans }
228*f0865ec9SKyle Evans
229*f0865ec9SKyle Evans ret = streebog256_final(&ctx, output);
230*f0865ec9SKyle Evans
231*f0865ec9SKyle Evans err:
232*f0865ec9SKyle Evans return ret;
233*f0865ec9SKyle Evans }
234*f0865ec9SKyle Evans
streebog256(const u8 * input,u32 ilen,u8 output[STREEBOG256_DIGEST_SIZE])235*f0865ec9SKyle Evans int streebog256(const u8 *input, u32 ilen, u8 output[STREEBOG256_DIGEST_SIZE])
236*f0865ec9SKyle Evans {
237*f0865ec9SKyle Evans int ret;
238*f0865ec9SKyle Evans streebog256_context ctx;
239*f0865ec9SKyle Evans
240*f0865ec9SKyle Evans ret = streebog256_init(&ctx); EG(ret, err);
241*f0865ec9SKyle Evans ret = streebog256_update(&ctx, input, ilen); EG(ret, err);
242*f0865ec9SKyle Evans ret = streebog256_final(&ctx, output);
243*f0865ec9SKyle Evans
244*f0865ec9SKyle Evans err:
245*f0865ec9SKyle Evans return ret;
246*f0865ec9SKyle Evans }
247*f0865ec9SKyle Evans
248*f0865ec9SKyle Evans #endif /* defined(WITH_HASH_STREEBOG256) */
249*f0865ec9SKyle Evans
250*f0865ec9SKyle Evans
251*f0865ec9SKyle Evans #if defined(WITH_HASH_STREEBOG512)
252*f0865ec9SKyle Evans
253*f0865ec9SKyle Evans /* Init */
streebog512_init(streebog512_context * ctx)254*f0865ec9SKyle Evans int streebog512_init(streebog512_context *ctx)
255*f0865ec9SKyle Evans {
256*f0865ec9SKyle Evans int ret;
257*f0865ec9SKyle Evans
258*f0865ec9SKyle Evans ret = streebog_init(ctx, STREEBOG512_DIGEST_SIZE, STREEBOG512_BLOCK_SIZE); EG(ret, err);
259*f0865ec9SKyle Evans
260*f0865ec9SKyle Evans ctx->magic = STREEBOG512_HASH_MAGIC;
261*f0865ec9SKyle Evans
262*f0865ec9SKyle Evans ret = 0;
263*f0865ec9SKyle Evans
264*f0865ec9SKyle Evans err:
265*f0865ec9SKyle Evans return ret;
266*f0865ec9SKyle Evans }
267*f0865ec9SKyle Evans
268*f0865ec9SKyle Evans /* Update */
streebog512_update(streebog512_context * ctx,const u8 * input,u32 ilen)269*f0865ec9SKyle Evans int streebog512_update(streebog512_context *ctx, const u8 *input, u32 ilen)
270*f0865ec9SKyle Evans {
271*f0865ec9SKyle Evans int ret;
272*f0865ec9SKyle Evans
273*f0865ec9SKyle Evans STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err);
274*f0865ec9SKyle Evans
275*f0865ec9SKyle Evans ret = streebog_update(ctx, input, ilen);
276*f0865ec9SKyle Evans
277*f0865ec9SKyle Evans err:
278*f0865ec9SKyle Evans return ret;
279*f0865ec9SKyle Evans }
280*f0865ec9SKyle Evans
281*f0865ec9SKyle Evans /* Finalize */
streebog512_final(streebog512_context * ctx,u8 output[STREEBOG512_DIGEST_SIZE])282*f0865ec9SKyle Evans int streebog512_final(streebog512_context *ctx,
283*f0865ec9SKyle Evans u8 output[STREEBOG512_DIGEST_SIZE])
284*f0865ec9SKyle Evans {
285*f0865ec9SKyle Evans int ret;
286*f0865ec9SKyle Evans
287*f0865ec9SKyle Evans STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err);
288*f0865ec9SKyle Evans
289*f0865ec9SKyle Evans ret = streebog_final(ctx, output); EG(ret, err);
290*f0865ec9SKyle Evans
291*f0865ec9SKyle Evans /* Uninit our context magic */
292*f0865ec9SKyle Evans ctx->magic = WORD(0);
293*f0865ec9SKyle Evans
294*f0865ec9SKyle Evans ret = 0;
295*f0865ec9SKyle Evans
296*f0865ec9SKyle Evans err:
297*f0865ec9SKyle Evans return ret;
298*f0865ec9SKyle Evans }
299*f0865ec9SKyle Evans
streebog512_scattered(const u8 ** inputs,const u32 * ilens,u8 output[STREEBOG512_DIGEST_SIZE])300*f0865ec9SKyle Evans int streebog512_scattered(const u8 **inputs, const u32 *ilens,
301*f0865ec9SKyle Evans u8 output[STREEBOG512_DIGEST_SIZE])
302*f0865ec9SKyle Evans {
303*f0865ec9SKyle Evans streebog512_context ctx;
304*f0865ec9SKyle Evans int pos = 0;
305*f0865ec9SKyle Evans int ret;
306*f0865ec9SKyle Evans
307*f0865ec9SKyle Evans MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
308*f0865ec9SKyle Evans
309*f0865ec9SKyle Evans ret = streebog512_init(&ctx); EG(ret, err);
310*f0865ec9SKyle Evans
311*f0865ec9SKyle Evans while (inputs[pos] != NULL) {
312*f0865ec9SKyle Evans ret = streebog512_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
313*f0865ec9SKyle Evans pos += 1;
314*f0865ec9SKyle Evans }
315*f0865ec9SKyle Evans
316*f0865ec9SKyle Evans ret = streebog512_final(&ctx, output);
317*f0865ec9SKyle Evans
318*f0865ec9SKyle Evans err:
319*f0865ec9SKyle Evans return ret;
320*f0865ec9SKyle Evans }
321*f0865ec9SKyle Evans
streebog512(const u8 * input,u32 ilen,u8 output[STREEBOG512_DIGEST_SIZE])322*f0865ec9SKyle Evans int streebog512(const u8 *input, u32 ilen, u8 output[STREEBOG512_DIGEST_SIZE])
323*f0865ec9SKyle Evans {
324*f0865ec9SKyle Evans int ret;
325*f0865ec9SKyle Evans streebog512_context ctx;
326*f0865ec9SKyle Evans
327*f0865ec9SKyle Evans ret = streebog512_init(&ctx); EG(ret, err);
328*f0865ec9SKyle Evans ret = streebog512_update(&ctx, input, ilen); EG(ret, err);
329*f0865ec9SKyle Evans ret = streebog512_final(&ctx, output);
330*f0865ec9SKyle Evans
331*f0865ec9SKyle Evans err:
332*f0865ec9SKyle Evans return ret;
333*f0865ec9SKyle Evans }
334*f0865ec9SKyle Evans
335*f0865ec9SKyle Evans #endif /* defined(WITH_HASH_STREEBOG512) */
336*f0865ec9SKyle Evans
337*f0865ec9SKyle Evans #else /* !(defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)) */
338*f0865ec9SKyle Evans /*
339*f0865ec9SKyle Evans * Dummy definition to avoid the empty translation unit ISO C warning
340*f0865ec9SKyle Evans */
341*f0865ec9SKyle Evans typedef int dummy;
342*f0865ec9SKyle Evans
343*f0865ec9SKyle Evans #endif /* defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512) */
344*f0865ec9SKyle Evans
345