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 <libecc/utils/utils.h>
12 #include <libecc/hash/shake.h>
13
14 /* Init function depending on the digest size */
_shake_init(shake_context * ctx,u8 digest_size,u8 block_size)15 int _shake_init(shake_context *ctx, u8 digest_size, u8 block_size)
16 {
17 int ret;
18
19 MUST_HAVE((ctx != NULL), ret, err);
20
21 /* Zeroize the internal state */
22 ret = local_memset(ctx->shake_state, 0, sizeof(ctx->shake_state)); EG(ret, err);
23
24 ctx->shake_idx = 0;
25 ctx->shake_digest_size = digest_size;
26 ctx->shake_block_size = block_size;
27
28 /* Detect endianness */
29 ctx->shake_endian = arch_is_big_endian() ? SHAKE_BIG : SHAKE_LITTLE;
30
31 err:
32 return ret;
33 }
34
35 /* Update hash function */
_shake_update(shake_context * ctx,const u8 * input,u32 ilen)36 int _shake_update(shake_context *ctx, const u8 *input, u32 ilen)
37 {
38 u32 i;
39 u8 *state;
40 int ret;
41
42 MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err);
43
44 state = (u8*)(ctx->shake_state);
45
46 for(i = 0; i < ilen; i++){
47 /* Compute the index depending on the endianness */
48 u64 idx = (ctx->shake_endian == SHAKE_LITTLE) ? ctx->shake_idx : SWAP64_Idx(ctx->shake_idx);
49 ctx->shake_idx++;
50 /* Update the state, and adapt endianness order */
51 state[idx] ^= input[i];
52 if(ctx->shake_idx == ctx->shake_block_size){
53 KECCAKF(ctx->shake_state);
54 ctx->shake_idx = 0;
55 }
56 }
57 ret = 0;
58
59 err:
60 return ret;
61 }
62
63 /* Finalize hash function */
_shake_finalize(shake_context * ctx,u8 * output)64 int _shake_finalize(shake_context *ctx, u8 *output)
65 {
66 unsigned int i;
67 u8 *state;
68 int ret;
69
70 MUST_HAVE((ctx != NULL) && (output != NULL), ret, err);
71 MUST_HAVE((ctx->shake_digest_size <= sizeof(ctx->shake_state)), ret, err);
72
73 state = (u8*)(ctx->shake_state);
74
75 /* Proceed with the padding of the last block */
76 /* Compute the index depending on the endianness */
77 if(ctx->shake_endian == SHAKE_LITTLE){
78 /* Little endian case */
79 state[ctx->shake_idx] ^= 0x1f;
80 state[ctx->shake_block_size - 1] ^= 0x80;
81 }
82 else{
83 /* Big endian case */
84 state[SWAP64_Idx(ctx->shake_idx)] ^= 0x1f;
85 state[SWAP64_Idx(ctx->shake_block_size - 1)] ^= 0x80;
86 }
87 /* Produce the output.
88 * NOTE: we should have a fixed version of SHAKE producing an output size
89 * with size less than the state size.
90 */
91 KECCAKF(ctx->shake_state);
92 for(i = 0; i < ctx->shake_digest_size; i++){
93 output[i] = (ctx->shake_endian == SHAKE_LITTLE) ? state[i] : state[SWAP64_Idx(i)];
94 }
95
96 /* Uninit our context magic */
97 ctx->magic = WORD(0);
98
99 ret = 0;
100
101 err:
102 return ret;
103 }
104