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 */ 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 */ 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 */ 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