Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/libecc/src/examples/hash/gostr34_11_94.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 "gostr34_11_94.h"
12
13
/* The 8 4-bit GOST block cipher encryption SBOX */
14
static const u8 gostr34_11_94_sbox_norm[8][16] =
15
{
16
{ 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 },
17
{ 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 },
18
{ 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 },
19
{ 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 },
20
{ 6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2 },
21
{ 4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14 },
22
{ 13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12 },
23
{ 1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12 }
24
};
25
26
static const u8 gostr34_11_94_sbox_rfc4357[8][16] =
27
{
28
{ 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15},
29
{ 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8},
30
{ 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13},
31
{ 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3},
32
{ 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5},
33
{ 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3},
34
{ 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11},
35
{ 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12}
36
};
37
38
39
/* Endianness handling */
40
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_arch_is_big_endian(void)
41
{
42
const u16 val = 0x0102;
43
const u8 *buf = (const u8 *)(&val);
44
45
return (buf[0] == 0x01);
46
}
47
48
/* A and P linear transformations */
49
static inline void gostr34_11_94_A(const u64 Y[GOSTR34_11_94_STATE_SIZE], u64 Y_[GOSTR34_11_94_STATE_SIZE])
50
{
51
u64 y1, y2, y3, y4;
52
53
y1 = Y[3];
54
y2 = Y[2];
55
y3 = Y[1];
56
y4 = Y[0];
57
58
Y_[0] = (y1 ^ y2);
59
Y_[1] = y4;
60
Y_[2] = y3;
61
Y_[3] = y2;
62
63
return;
64
}
65
66
static inline void gostr34_11_94_P(const u64 Y[GOSTR34_11_94_STATE_SIZE], u64 Y_[GOSTR34_11_94_STATE_SIZE])
67
{
68
unsigned int i, k;
69
70
const u8 *y = (const u8*)Y;
71
u8 *y_ = (u8*)Y_;
72
73
for(i = 0; i < 4; i++){
74
for(k = 1; k < 9; k++){
75
unsigned int phi_idx = (8 * GOSTR34_11_94_STATE_SIZE) - (i + (4 * (k - 1)));
76
unsigned int phi = ((8 * i) + k);
77
y_[phi_idx - 1] = y[phi - 1];
78
}
79
}
80
return;
81
}
82
83
/* GOSTR34_11_94 key generation constants */
84
static const u64 gostr34_11_94_C[3][GOSTR34_11_94_STATE_SIZE] = {
85
{ 0, 0, 0, 0 },
86
{ 0xff000000ffff00ffULL, 0x00ffff00ff0000ffULL, 0xff00ff00ff00ff00ULL, 0x00ff00ff00ff00ffULL },
87
{ 0, 0, 0, 0 },
88
};
89
90
/* GOSTR34_11_94 key generation */
91
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_key_generation(const u64 H[GOSTR34_11_94_STATE_SIZE], const u64 M[GOSTR34_11_94_STATE_SIZE], u64 K[4][GOSTR34_11_94_STATE_SIZE])
92
{
93
/* U, V, W */
94
u64 U[GOSTR34_11_94_STATE_SIZE], V[GOSTR34_11_94_STATE_SIZE], W[GOSTR34_11_94_STATE_SIZE];
95
unsigned int i, j;
96
int ret;
97
98
/* U = H */
99
ret = local_memcpy(U, H, sizeof(U)); EG(ret, err);
100
/* V = M */
101
ret = local_memcpy(V, M, sizeof(V)); EG(ret, err);
102
/* W = U ^ V */
103
for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){
104
W[j] = (U[j] ^ V[j]);
105
}
106
/* K1 = P(W) */
107
gostr34_11_94_P(W, K[0]);
108
109
for(i = 1; i < 4; i++){
110
/* U = A(U) ^ C */
111
gostr34_11_94_A(U, U);
112
for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){
113
u64 C;
114
GET_UINT64_LE(C, (const u8*)&gostr34_11_94_C[i - 1][j], 0);
115
U[j] = (u64)(U[j] ^ C);
116
}
117
/* V = A(A(V)) */
118
gostr34_11_94_A(V, V);
119
gostr34_11_94_A(V, V);
120
/* W = U ^ V */
121
for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){
122
W[j] = (u64)(U[j] ^ V[j]);
123
}
124
/* Ki = P(W) */
125
gostr34_11_94_P(W, K[i]);
126
}
127
128
ret = 0;
129
130
err:
131
return ret;
132
}
133
134
/* GOSTR34_11_94 state encryption */
135
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_block_encryption(const u64 K[GOSTR34_11_94_STATE_SIZE], const u64 P, u64 *E, const u8 sbox[8][16])
136
{
137
int ret;
138
unsigned int round, i;
139
u32 R_i, L_i, R_i1 = 0, L_i1 = 0;
140
const u8 *p = (const u8*)&P;
141
u8 *e = (u8*)E;
142
143
MUST_HAVE((K != NULL) && (sbox != NULL) && (E != NULL), ret, err);
144
145
/* The encryption is a Feistel network */
146
GET_UINT32_BE(L_i, p, 0);
147
GET_UINT32_BE(R_i, p, 4);
148
for(round = 0; round < 32; round++){
149
u32 sk;
150
const u8 *k = (const u8*)K;
151
u8 *r_i1 = (u8 *)&R_i1;
152
153
/* Key schedule */
154
if(round < 24){
155
GET_UINT32_LE(sk, k, (4 * (round % 8)));
156
}
157
else{
158
GET_UINT32_LE(sk, k, (4 * (7 - (round % 8))));
159
}
160
/*** Feistel round ***/
161
R_i1 = (u32)(R_i + sk); /* add round key */
162
/* SBox layer */
163
for(i = 0; i < 4; i++){
164
unsigned int sb_idx;
165
if(gostr34_11_94_arch_is_big_endian()){
166
sb_idx = (2 * (3 - i));
167
}
168
else{
169
sb_idx = (2 * i);
170
}
171
r_i1[i] = (u8)((sbox[sb_idx + 1][(r_i1[i] & 0xf0) >> 4] << 4) | (sbox[sb_idx][(r_i1[i] & 0x0f)]));
172
}
173
/* Rotation by 11 and XOR with L */
174
R_i1 = (u32)(ROTL_GOSTR34_11_94(R_i1, 11) ^ L_i);
175
/* Feistel */
176
L_i1 = R_i;
177
/* Next round */
178
R_i = R_i1;
179
L_i = L_i1;
180
}
181
/* Output */
182
PUT_UINT32_LE(L_i1, e, 0);
183
PUT_UINT32_LE(R_i1, e, 4);
184
185
ret = 0;
186
187
err:
188
return ret;
189
}
190
191
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_encryption(const u64 K[4][GOSTR34_11_94_STATE_SIZE], const u64 H[GOSTR34_11_94_STATE_SIZE], u64 S[GOSTR34_11_94_STATE_SIZE], const u8 sbox[8][16])
192
{
193
int ret;
194
195
196
MUST_HAVE((GOSTR34_11_94_STATE_SIZE == 4), ret, err);
197
/* Return S = s4 s3 s2 s1 */
198
/* s1 = E(h1, K1) */
199
ret = gostr34_11_94_block_encryption(K[0], H[3], &S[0], sbox); EG(ret, err);
200
/* s2 = E(h2, K2) */
201
ret = gostr34_11_94_block_encryption(K[1], H[2], &S[1], sbox); EG(ret, err);
202
/* s3 = E(h3, K3) */
203
ret = gostr34_11_94_block_encryption(K[2], H[1], &S[2], sbox); EG(ret, err);
204
/* s4 = E(h4, K4) */
205
ret = gostr34_11_94_block_encryption(K[3], H[0], &S[3], sbox); EG(ret, err);
206
207
ret = 0;
208
209
err:
210
return ret;
211
}
212
213
/*
214
* NOTE: we use a somehow "artificial" union here in order to deal with
215
* possible alignment issues in the gostr34_11_94_state_psi function
216
* (as we have to interpret an array of 4 u64 into an array of 16 u16
217
* in order to apply our Psi function).
218
*/
219
typedef union {
220
u64 A[GOSTR34_11_94_STATE_SIZE];
221
u16 B[16];
222
} gostr34_11_94_union;
223
224
/* GOSTR34_11_94 output transformation */
225
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_psi(const u64 G[GOSTR34_11_94_STATE_SIZE], u64 G_[GOSTR34_11_94_STATE_SIZE])
226
{
227
int ret;
228
unsigned int i;
229
/* Use our unions in order to deal with alignment issues
230
* (see the rationale above).
231
*/
232
gostr34_11_94_union G_copy;
233
gostr34_11_94_union *g = &G_copy;
234
gostr34_11_94_union *g_ = (gostr34_11_94_union*)G_;
235
236
/* Better safe than sorry ... */
237
MUST_HAVE((sizeof(gostr34_11_94_union) == (sizeof(u64) * GOSTR34_11_94_STATE_SIZE)), ret, err);
238
239
/* Copy input */
240
ret = local_memcpy(g, G, sizeof(gostr34_11_94_union)); EG(ret, err);
241
242
/* ψ(Γ) = (γ0 ⊕ γ1 ⊕ γ2 ⊕ γ3 ⊕ γ12 ⊕ γ15) γ15 γ14 · · · γ1
243
* where Γ is split into sixteen 16-bit words, i.e. Γ = γ15 γ14 · · · γ0.
244
*/
245
for(i = 0; i < 15; i++){
246
g_->B[i] = g->B[i + 1];
247
}
248
g_->B[15] = (u16)((g->B[0]) ^ (g->B[1]) ^ (g->B[2]) ^ (g->B[3]) ^ (g->B[12]) ^ (g->B[15]));
249
250
ret = 0;
251
252
err:
253
return ret;
254
}
255
256
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_output_transform(const u64 H[GOSTR34_11_94_STATE_SIZE], const u64 S[GOSTR34_11_94_STATE_SIZE], const u64 M[GOSTR34_11_94_STATE_SIZE], u64 H_[GOSTR34_11_94_STATE_SIZE])
257
{
258
unsigned int i;
259
int ret;
260
261
/* Compute psi^12 of S */
262
ret = local_memcpy(H_, S, GOSTR34_11_94_STATE_SIZE * sizeof(u64)); EG(ret, err);
263
for(i = 0; i < 12; i++){
264
ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);
265
}
266
/* Compute M xor psi^12 */
267
for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){
268
u64 m;
269
if(gostr34_11_94_arch_is_big_endian()){
270
GET_UINT64_LE(m, (const u8*)&M[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
271
}
272
else{
273
GET_UINT64_BE(m, (const u8*)&M[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
274
}
275
H_[i] = (u64)(H_[i] ^ m);
276
}
277
ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);
278
/* Xor it with H */
279
for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){
280
u64 h;
281
if(gostr34_11_94_arch_is_big_endian()){
282
GET_UINT64_LE(h, (const u8*)&H[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
283
}
284
else{
285
GET_UINT64_BE(h, (const u8*)&H[GOSTR34_11_94_STATE_SIZE - i - 1], 0);
286
}
287
H_[i] = (u64)(H_[i] ^ h);
288
}
289
/* Now compute psi^61 */
290
for(i = 0; i < 61; i++){
291
ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);
292
}
293
294
ret = 0;
295
296
err:
297
return ret;
298
}
299
300
/* GOSTR34_11_94 256-bit words summing (a simple adder with carry in constant time) */
301
static inline void gostr34_11_94_256bit_sum(const u64 A[GOSTR34_11_94_STATE_SIZE], const u64 B[GOSTR34_11_94_STATE_SIZE], u64 C[GOSTR34_11_94_STATE_SIZE])
302
{
303
unsigned int i;
304
u64 tmp, carry1, carry2, _carry;
305
306
_carry = 0;
307
for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){
308
u64 a, b, c;
309
unsigned int idx = (GOSTR34_11_94_STATE_SIZE - i - 1);
310
GET_UINT64_BE(a, (const u8*)(&A[idx]), 0);
311
GET_UINT64_BE(b, (const u8*)(&B[idx]), 0);
312
tmp = (u64)(a + b);
313
carry1 = (u64)(tmp < a);
314
c = (u64)(tmp + _carry);
315
carry2 = (u64)(c < tmp);
316
_carry = (u64)(carry1 | carry2);
317
PUT_UINT64_BE(c, (u8*)(&C[idx]), 0);
318
}
319
320
return;
321
}
322
323
/* GOSTR34_11_94 core processing. Returns 0 on success, -1 on error. */
324
ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_process(gostr34_11_94_context *ctx,
325
const u8 data[GOSTR34_11_94_BLOCK_SIZE])
326
{
327
int ret;
328
unsigned int i;
329
u64 K[4][GOSTR34_11_94_STATE_SIZE];
330
u64 H[GOSTR34_11_94_STATE_SIZE], S[GOSTR34_11_94_STATE_SIZE], M[GOSTR34_11_94_STATE_SIZE];
331
332
MUST_HAVE((data != NULL), ret, err);
333
GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
334
/* Get our local data in little endian format */
335
for(i = 0; i < GOSTR34_11_94_BLOCK_SIZE; i++){
336
((u8*)M)[i] = data[GOSTR34_11_94_BLOCK_SIZE - i - 1];
337
}
338
/* Get the saved state */
339
for(i = 0; i < GOSTR34_11_94_BLOCK_SIZE; i++){
340
((u8*)H)[i] = ((u8*)ctx->gostr34_11_94_state)[GOSTR34_11_94_BLOCK_SIZE - i - 1];
341
}
342
343
/* Key generation */
344
ret = gostr34_11_94_key_generation(H, M, K); EG(ret, err);
345
/* State encryption */
346
switch(ctx->gostr34_11_94_t){
347
case GOST34_11_94_NORM:{
348
ret = gostr34_11_94_state_encryption((const u64 (*)[4])K, H, S, gostr34_11_94_sbox_norm); EG(ret, err);
349
break;
350
}
351
case GOST34_11_94_RFC4357:{
352
ret = gostr34_11_94_state_encryption((const u64 (*)[4])K, H, S, gostr34_11_94_sbox_rfc4357); EG(ret, err);
353
break;
354
}
355
default:{
356
ret = -1;
357
goto err;
358
}
359
}
360
/* Output transformation */
361
ret = gostr34_11_94_state_output_transform(H, S, M, ctx->gostr34_11_94_state); EG(ret, err);
362
/* Update the internal sum */
363
gostr34_11_94_256bit_sum(ctx->gostr34_11_94_sum, M, ctx->gostr34_11_94_sum);
364
365
ret = 0;
366
367
err:
368
return ret;
369
}
370
371
/* Init hash function. Returns 0 on success, -1 on error. */
372
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_init(gostr34_11_94_context *ctx)
373
{
374
int ret;
375
376
MUST_HAVE((ctx != NULL), ret, err);
377
378
/* Sanity check on size */
379
MUST_HAVE((GOSTR34_11_94_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);
380
381
ctx->gostr34_11_94_total = 0;
382
ctx->gostr34_11_94_state[0] = 0;
383
ctx->gostr34_11_94_state[1] = 0;
384
ctx->gostr34_11_94_state[2] = 0;
385
ctx->gostr34_11_94_state[3] = 0;
386
387
ret = local_memset(ctx->gostr34_11_94_sum, 0, sizeof(ctx->gostr34_11_94_sum)); EG(ret, err);
388
389
/* Our default GOST34_11_94 type is GOST34_11_94_NORM */
390
ctx->gostr34_11_94_t = GOST34_11_94_NORM;
391
392
/* Tell that we are initialized */
393
ctx->magic = GOSTR34_11_94_HASH_MAGIC;
394
395
ret = 0;
396
397
err:
398
return ret;
399
}
400
401
/* Function to modify the initial IV as it is not imposed by the RFCs */
402
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_set_iv(gostr34_11_94_context *ctx, const u64 iv[GOSTR34_11_94_STATE_SIZE])
403
{
404
int ret;
405
406
MUST_HAVE((iv != NULL), ret, err);
407
GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
408
409
/* We cannot change the IV after the first update */
410
MUST_HAVE((ctx->gostr34_11_94_total == 0), ret, err);
411
412
ctx->gostr34_11_94_state[0] = iv[0];
413
ctx->gostr34_11_94_state[1] = iv[1];
414
ctx->gostr34_11_94_state[2] = iv[2];
415
ctx->gostr34_11_94_state[3] = iv[3];
416
417
ret = 0;
418
419
err:
420
return ret;
421
}
422
423
/* Function to modify the GOST type (that will dictate the underlying SBOX to use for block encryption) */
424
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_set_type(gostr34_11_94_context *ctx, gostr34_11_94_type type)
425
{
426
int ret;
427
428
GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
429
430
/* We cannot change the algorithm type after the first update */
431
MUST_HAVE((ctx->gostr34_11_94_total == 0), ret, err);
432
433
if((type != GOST34_11_94_NORM) && (type != GOST34_11_94_RFC4357)){
434
ret = -1;
435
goto err;
436
}
437
438
ctx->gostr34_11_94_t = type;
439
440
ret = 0;
441
442
err:
443
return ret;
444
}
445
446
447
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_update(gostr34_11_94_context *ctx, const u8 *input, u32 ilen)
448
{
449
const u8 *data_ptr = input;
450
u32 remain_ilen = ilen;
451
u16 fill;
452
u8 left;
453
int ret;
454
455
MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
456
GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
457
458
/* Nothing to process, return */
459
if (ilen == 0) {
460
ret = 0;
461
goto err;
462
}
463
464
/* Get what's left in our local buffer */
465
left = (ctx->gostr34_11_94_total & 0x3F);
466
fill = (u16)(GOSTR34_11_94_BLOCK_SIZE - left);
467
468
ctx->gostr34_11_94_total += ilen;
469
470
if ((left > 0) && (remain_ilen >= fill)) {
471
/* Copy data at the end of the buffer */
472
ret = local_memcpy(ctx->gostr34_11_94_buffer + left, data_ptr, fill); EG(ret, err);
473
ret = gostr34_11_94_process(ctx, ctx->gostr34_11_94_buffer); EG(ret, err);
474
data_ptr += fill;
475
remain_ilen -= fill;
476
left = 0;
477
}
478
479
while (remain_ilen >= GOSTR34_11_94_BLOCK_SIZE) {
480
ret = gostr34_11_94_process(ctx, data_ptr); EG(ret, err);
481
data_ptr += GOSTR34_11_94_BLOCK_SIZE;
482
remain_ilen -= GOSTR34_11_94_BLOCK_SIZE;
483
}
484
485
if (remain_ilen > 0) {
486
ret = local_memcpy(ctx->gostr34_11_94_buffer + left, data_ptr, remain_ilen); EG(ret, err);
487
}
488
489
ret = 0;
490
491
err:
492
return ret;
493
}
494
495
/* Finalize. Returns 0 on success, -1 on error.*/
496
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_final(gostr34_11_94_context *ctx, u8 output[GOSTR34_11_94_DIGEST_SIZE])
497
{
498
unsigned int block_present = 0;
499
u8 last_padded_block[2 * GOSTR34_11_94_BLOCK_SIZE];
500
int ret;
501
502
MUST_HAVE((output != NULL), ret, err);
503
GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);
504
505
/* This is our final step, so we proceed with the padding if necessary */
506
/* Fill in our last block with zeroes */
507
ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
508
509
block_present = ctx->gostr34_11_94_total % GOSTR34_11_94_BLOCK_SIZE;
510
/* Copy what's left in our temporary context buffer */
511
ret = local_memcpy(last_padded_block, ctx->gostr34_11_94_buffer,
512
block_present); EG(ret, err);
513
514
/* Put in the second block the size in bits of the message in bits in little endian */
515
PUT_UINT64_LE(8 * ctx->gostr34_11_94_total, last_padded_block, GOSTR34_11_94_BLOCK_SIZE);
516
517
if(block_present != 0){
518
/* Process padding block if necessary */
519
ret = gostr34_11_94_process(ctx, last_padded_block); EG(ret, err);
520
}
521
/* Copy our sum in the beginning of the block */
522
if(gostr34_11_94_arch_is_big_endian()){
523
PUT_UINT64_LE(ctx->gostr34_11_94_sum[3], last_padded_block, 0);
524
PUT_UINT64_LE(ctx->gostr34_11_94_sum[2], last_padded_block, 8);
525
PUT_UINT64_LE(ctx->gostr34_11_94_sum[1], last_padded_block, 16);
526
PUT_UINT64_LE(ctx->gostr34_11_94_sum[0], last_padded_block, 24);
527
}
528
else{
529
PUT_UINT64_BE(ctx->gostr34_11_94_sum[3], last_padded_block, 0);
530
PUT_UINT64_BE(ctx->gostr34_11_94_sum[2], last_padded_block, 8);
531
PUT_UINT64_BE(ctx->gostr34_11_94_sum[1], last_padded_block, 16);
532
PUT_UINT64_BE(ctx->gostr34_11_94_sum[0], last_padded_block, 24);
533
}
534
535
/* Process the "size" in bits block */
536
ret = gostr34_11_94_process(ctx, last_padded_block + GOSTR34_11_94_BLOCK_SIZE); EG(ret, err);
537
/* Process the message blocks sum */
538
ret = gostr34_11_94_process(ctx, last_padded_block); EG(ret, err);
539
540
/* Output the hash result */
541
if(gostr34_11_94_arch_is_big_endian()){
542
PUT_UINT64_BE(ctx->gostr34_11_94_state[0], output, 0);
543
PUT_UINT64_BE(ctx->gostr34_11_94_state[1], output, 8);
544
PUT_UINT64_BE(ctx->gostr34_11_94_state[2], output, 16);
545
PUT_UINT64_BE(ctx->gostr34_11_94_state[3], output, 24);
546
}
547
else{
548
PUT_UINT64_LE(ctx->gostr34_11_94_state[0], output, 0);
549
PUT_UINT64_LE(ctx->gostr34_11_94_state[1], output, 8);
550
PUT_UINT64_LE(ctx->gostr34_11_94_state[2], output, 16);
551
PUT_UINT64_LE(ctx->gostr34_11_94_state[3], output, 24);
552
}
553
554
/* Tell that we are uninitialized */
555
ctx->magic = WORD(0);
556
557
ret = 0;
558
559
err:
560
return ret;
561
}
562
563
564
/*
565
* Scattered version performing init/update/finalize on a vector of buffers
566
* 'inputs' with the length of each buffer passed via 'ilens'. The function
567
* loops on pointers in 'inputs' until it finds a NULL pointer. The function
568
* returns 0 on success, -1 on error.
569
*/
570
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered(const u8 **inputs, const u32 *ilens,
571
u8 output[GOSTR34_11_94_DIGEST_SIZE], gostr34_11_94_type type)
572
{
573
gostr34_11_94_context ctx;
574
int ret, pos = 0;
575
576
MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
577
578
ret = gostr34_11_94_init(&ctx); EG(ret, err);
579
ret = gostr34_11_94_set_type(&ctx, type); EG(ret, err);
580
581
while (inputs[pos] != NULL) {
582
ret = gostr34_11_94_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
583
pos += 1;
584
}
585
586
ret = gostr34_11_94_final(&ctx, output);
587
588
err:
589
return ret;
590
}
591
592
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered_norm(const u8 **inputs, const u32 *ilens,
593
u8 output[GOSTR34_11_94_DIGEST_SIZE])
594
{
595
return gostr34_11_94_scattered(inputs, ilens, output, GOST34_11_94_NORM);
596
}
597
598
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered_rfc4357(const u8 **inputs, const u32 *ilens,
599
u8 output[GOSTR34_11_94_DIGEST_SIZE])
600
{
601
return gostr34_11_94_scattered(inputs, ilens, output, GOST34_11_94_RFC4357);
602
}
603
604
605
/*
606
* Single call version performing init/update/final on given input.
607
* Returns 0 on success, -1 on error.
608
*/
609
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE], gostr34_11_94_type type)
610
{
611
gostr34_11_94_context ctx;
612
int ret;
613
614
ret = gostr34_11_94_init(&ctx); EG(ret, err);
615
ret = gostr34_11_94_set_type(&ctx, type); EG(ret, err);
616
ret = gostr34_11_94_update(&ctx, input, ilen); EG(ret, err);
617
ret = gostr34_11_94_final(&ctx, output);
618
619
err:
620
return ret;
621
}
622
623
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_norm(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE])
624
{
625
return gostr34_11_94(input, ilen, output, GOST34_11_94_NORM);
626
}
627
628
ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_rfc4357(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE])
629
{
630
return gostr34_11_94(input, ilen, output, GOST34_11_94_RFC4357);
631
}
632
633