1 /* 2 * Copyright (C) 2022 - 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 #ifndef __BASH_H__ 12 #define __BASH_H__ 13 14 #include <libecc/words/words.h> 15 16 /* 17 * This is an implementation of the BASH hash functions family (for sizes 224, 256, 384 and 512) 18 * following the standard STB 34.101.77-2020 (http://apmi.bsu.by/assets/files/std/bash-spec24.pdf). 19 * An english version of the specifications exist here: https://eprint.iacr.org/2016/587.pdf 20 */ 21 22 #define _BASH_ROTHI_(x, y) (((x) << (y)) | ((x) >> ((sizeof(u64) * 8) - (y)))) 23 24 /* We handle the case where one of the shifts is more than 64-bit: in this 25 * case, behaviour is undefined as per ANSI C definition. In this case, we 26 * return the untouched input. 27 */ 28 #define BASH_ROTHI(x, y) ((((y) < (sizeof(u64) * 8)) && ((y) > 0)) ? (_BASH_ROTHI_(x, y)) : (x)) 29 30 /* 31 * Round transformation of the state. Notations are the 32 * same as the ones used in: 33 * https://eprint.iacr.org/2016/587.pdf 34 */ 35 #define BASH_SLICES_X 3 36 #define BASH_SLICES_Y 8 37 #define BASH_ROT_ROUNDS 8 38 #define BASH_ROT_IDX 4 39 #define BASH_ROUNDS 24 40 41 #define BASH_L3_S3(W0, W1, W2, m1, n1, m2, n2) do { \ 42 u64 T0, T1, T2; \ 43 T0 = BASH_ROTHI(W0, m1); \ 44 W0 = (W0 ^ W1 ^ W2); \ 45 T1 = (W1 ^ BASH_ROTHI(W0, n1)); \ 46 W1 = (T0 ^ T1); \ 47 W2 = (W2 ^ BASH_ROTHI(W2, m2) ^ BASH_ROTHI(T1, n2)); \ 48 T0 = (~(W2)); \ 49 T1 = (W0 | W2); \ 50 T2 = (W0 & W1); \ 51 T0 = (T0 | W1); \ 52 W1 = (W1 ^ T1); \ 53 W2 = (W2 ^ T2); \ 54 W0 = (W0 ^ T0); \ 55 } while(0) 56 57 #define BASH_PERMUTE(S) do { \ 58 u64 S_[BASH_SLICES_X * BASH_SLICES_Y]; \ 59 IGNORE_RET_VAL(local_memcpy(S_, S, sizeof(S_))); \ 60 S[ 0] = S_[15]; S[ 1] = S_[10]; S[ 2] = S_[ 9]; S[ 3] = S_[12]; \ 61 S[ 4] = S_[11]; S[ 5] = S_[14]; S[ 6] = S_[13]; S[ 7] = S_[ 8]; \ 62 S[ 8] = S_[17]; S[ 9] = S_[16]; S[10] = S_[19]; S[11] = S_[18]; \ 63 S[12] = S_[21]; S[13] = S_[20]; S[14] = S_[23]; S[15] = S_[22]; \ 64 S[16] = S_[ 6]; S[17] = S_[ 3]; S[18] = S_[ 0]; S[19] = S_[ 5]; \ 65 S[20] = S_[ 2]; S[21] = S_[ 7]; S[22] = S_[ 4]; S[23] = S_[ 1]; \ 66 } while(0) 67 68 static const u64 bash_rc[BASH_ROUNDS] = 69 { 70 0x3bf5080ac8ba94b1ULL, 71 0xc1d1659c1bbd92f6ULL, 72 0x60e8b2ce0ddec97bULL, 73 0xec5fb8fe790fbc13ULL, 74 0xaa043de6436706a7ULL, 75 0x8929ff6a5e535bfdULL, 76 0x98bf1e2c50c97550ULL, 77 0x4c5f8f162864baa8ULL, 78 0x262fc78b14325d54ULL, 79 0x1317e3c58a192eaaULL, 80 0x098bf1e2c50c9755ULL, 81 0xd8ee19681d669304ULL, 82 0x6c770cb40eb34982ULL, 83 0x363b865a0759a4c1ULL, 84 0xc73622b47c4c0aceULL, 85 0x639b115a3e260567ULL, 86 0xede6693460f3da1dULL, 87 0xaad8d5034f9935a0ULL, 88 0x556c6a81a7cc9ad0ULL, 89 0x2ab63540d3e64d68ULL, 90 0x155b1aa069f326b4ULL, 91 0x0aad8d5034f9935aULL, 92 0x0556c6a81a7cc9adULL, 93 0xde8082cd72debc78ULL, 94 }; 95 96 static const u8 bash_rot[BASH_ROT_ROUNDS][BASH_ROT_IDX] = 97 { 98 { 8, 53, 14, 1 }, 99 { 56, 51, 34, 7 }, 100 { 8, 37, 46, 49 }, 101 { 56, 3, 2, 23 }, 102 { 8, 21, 14, 33 }, 103 { 56, 19, 34, 39 }, 104 { 8, 5, 46, 17 }, 105 { 56, 35, 2, 55 }, 106 }; 107 108 /* Macro to handle endianness conversion */ 109 #define SWAP64(A) do { \ 110 A = ((A) << 56 | ((A) & 0xff00) << 40 | ((A) & 0xff0000) << 24 | \ 111 ((A) & 0xff000000) << 8 | ((A) >> 8 & 0xff000000) | \ 112 ((A) >> 24 & 0xff0000) | ((A) >> 40 & 0xff00) | (A) >> 56); \ 113 } while(0) 114 115 /* The main Bash-f core as descibed in the specification. */ 116 #define BASHF(S, end) do { \ 117 unsigned int round, i; \ 118 /* Swap endianness if necessary */ \ 119 if(end == BASH_BIG){ \ 120 for(i = 0; i < (BASH_SLICES_X * BASH_SLICES_Y); i++){ \ 121 SWAP64(S[i]); \ 122 } \ 123 } \ 124 for(round = 0; round < BASH_ROUNDS; round++){ \ 125 unsigned int v; \ 126 for(v = 0; v < 8; v++){ \ 127 BASH_L3_S3(S[v], S[v+8], S[v+16], bash_rot[v][0], bash_rot[v][1], \ 128 bash_rot[v][2], bash_rot[v][3]); \ 129 } \ 130 BASH_PERMUTE(S); \ 131 S[23] ^= bash_rc[round]; \ 132 } \ 133 /* Swap back endianness if necessary */ \ 134 if(end == BASH_BIG){ \ 135 for(i = 0; i < (BASH_SLICES_X * BASH_SLICES_Y); i++){ \ 136 SWAP64(S[i]); \ 137 } \ 138 } \ 139 } while(0) 140 141 typedef enum { 142 BASH_LITTLE = 0, 143 BASH_BIG = 1, 144 } bash_endianness; 145 146 typedef struct bash_context_ { 147 u8 bash_digest_size; 148 u8 bash_block_size; 149 bash_endianness bash_endian; 150 /* Local counter */ 151 u64 bash_total; 152 /* Bash state */ 153 u64 bash_state[BASH_SLICES_X * BASH_SLICES_Y]; 154 /* Initialization magic value */ 155 u64 magic; 156 } bash_context; 157 158 ATTRIBUTE_WARN_UNUSED_RET int _bash_init(bash_context *ctx, uint8_t digest_size); 159 ATTRIBUTE_WARN_UNUSED_RET int _bash_update(bash_context *ctx, const uint8_t *buf, uint32_t buflen); 160 ATTRIBUTE_WARN_UNUSED_RET int _bash_finalize(bash_context *ctx, uint8_t *output); 161 162 #endif /* __BASH_H__ */ 163