1 /* 2 * Copyright (C) 2021 - This file is part of libecc project 3 * 4 * Authors: 5 * Ryad BENADJILA <ryadbenadjila@gmail.com> 6 * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 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