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