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/lib_ecc_config.h> 12 #if defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512) 13 14 /* 15 * NOTE: we put STREEBOG256 and STREEBOG512 in the same compilation unit on 16 * purpose, so that we avoid duplicating the rather big tables that are shared 17 * between the two digest versions. 18 */ 19 20 #include <libecc/utils/utils.h> 21 #if defined(WITH_HASH_STREEBOG256) 22 #include <libecc/hash/streebog256.h> 23 #endif 24 #if defined(WITH_HASH_STREEBOG512) 25 #include <libecc/hash/streebog512.h> 26 #endif 27 28 /*** Generic functions for both STREEBOG256 and STREEBOG512 ***/ 29 /* Init */ 30 ATTRIBUTE_WARN_UNUSED_RET static int streebog_init(streebog_context *ctx, u8 digest_size, u8 block_size) 31 { 32 int ret; 33 34 /* Sanity check */ 35 MUST_HAVE((digest_size == STREEBOG256_DIGEST_SIZE) || (digest_size == STREEBOG512_DIGEST_SIZE), ret, err); 36 37 MUST_HAVE((ctx != NULL), ret, err); 38 39 /* Zeroize the internal state */ 40 ret = local_memset(ctx, 0, sizeof(streebog_context)); EG(ret, err); 41 42 if(digest_size == 32){ 43 ret = local_memset(ctx->h, 1, sizeof(ctx->h)); EG(ret, err); 44 } 45 46 /* Initialize our digest size and block size */ 47 ctx->streebog_digest_size = digest_size; 48 ctx->streebog_block_size = block_size; 49 /* Detect endianness */ 50 ctx->streebog_endian = arch_is_big_endian() ? STREEBOG_BIG : STREEBOG_LITTLE; 51 52 err: 53 return ret; 54 } 55 56 ATTRIBUTE_WARN_UNUSED_RET static int streebog_update(streebog_context *ctx, const u8 *input, u32 ilen) 57 { 58 const u8 *data_ptr = input; 59 u32 remain_ilen = ilen; 60 u16 fill; 61 u8 left; 62 int ret; 63 64 MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err); 65 66 /* Nothing to process, return */ 67 if (ilen == 0) { 68 ret = 0; 69 goto err; 70 } 71 72 /* Get what's left in our local buffer */ 73 left = (ctx->streebog_total & 0x3F); 74 fill = (u16)(STREEBOG_BLOCK_SIZE - left); 75 76 ctx->streebog_total += ilen; 77 78 if ((left > 0) && (remain_ilen >= fill)) { 79 /* Copy data at the end of the buffer */ 80 ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, fill); EG(ret, err); 81 streebog_process(ctx, ctx->streebog_buffer, (8 * STREEBOG_BLOCK_SIZE)); 82 data_ptr += fill; 83 remain_ilen -= fill; 84 left = 0; 85 } 86 87 while (remain_ilen >= STREEBOG_BLOCK_SIZE) { 88 streebog_process(ctx, data_ptr, (8 * STREEBOG_BLOCK_SIZE)); 89 data_ptr += STREEBOG_BLOCK_SIZE; 90 remain_ilen -= STREEBOG_BLOCK_SIZE; 91 } 92 93 if (remain_ilen > 0) { 94 ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, remain_ilen); EG(ret, err); 95 } 96 97 ret = 0; 98 99 err: 100 return ret; 101 } 102 103 ATTRIBUTE_WARN_UNUSED_RET static int streebog_final(streebog_context *ctx, u8 *output) 104 { 105 unsigned int block_present = 0; 106 u8 last_padded_block[STREEBOG_BLOCK_SIZE]; 107 u64 Z[STREEBOG_BLOCK_U64_SIZE]; 108 unsigned int j; 109 u8 digest_size; 110 u8 idx; 111 int ret; 112 113 MUST_HAVE((ctx != NULL) && (output != NULL), ret, err); 114 115 digest_size = ctx->streebog_digest_size; 116 /* Sanity check */ 117 MUST_HAVE((digest_size == 32) || (digest_size == 64), ret, err); 118 119 /* Zero init our Z */ 120 ret = local_memset(Z, 0, sizeof(Z)); EG(ret, err); 121 122 /* Fill in our last block with zeroes */ 123 ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err); 124 125 /* This is our final step, so we proceed with the padding */ 126 block_present = (ctx->streebog_total % STREEBOG_BLOCK_SIZE); 127 if (block_present != 0) { 128 /* Copy what's left in our temporary context buffer */ 129 ret = local_memcpy(last_padded_block, ctx->streebog_buffer, 130 block_present); EG(ret, err); 131 } 132 133 /* Put the 0x01 byte, beginning of padding */ 134 last_padded_block[block_present] = 0x01; 135 136 streebog_process(ctx, last_padded_block, (8 * (ctx->streebog_total % STREEBOG_BLOCK_SIZE))); 137 138 gN(ctx->h, ctx->N, Z); 139 gN(ctx->h, ctx->Sigma, Z); 140 141 for(j = 0; j < STREEBOG_BLOCK_U64_SIZE; j++){ 142 ctx->h[j] = S64(ctx->h[j]); 143 } 144 145 idx = 0; 146 147 if(digest_size == 64){ 148 /* 512-bit hash case */ 149 STREEBOG_PUT_UINT64(ctx->h[0], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 150 STREEBOG_PUT_UINT64(ctx->h[1], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 151 STREEBOG_PUT_UINT64(ctx->h[2], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 152 STREEBOG_PUT_UINT64(ctx->h[3], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 153 } 154 /* 256 and 512-bit hash case */ 155 STREEBOG_PUT_UINT64(ctx->h[4], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 156 STREEBOG_PUT_UINT64(ctx->h[5], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 157 STREEBOG_PUT_UINT64(ctx->h[6], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8); 158 STREEBOG_PUT_UINT64(ctx->h[7], output, idx, ctx->streebog_endian); 159 160 ret = 0; 161 162 err: 163 return ret; 164 } 165 166 #if defined(WITH_HASH_STREEBOG256) 167 168 /* Init */ 169 int streebog256_init(streebog256_context *ctx) 170 { 171 int ret; 172 173 ret = streebog_init(ctx, STREEBOG256_DIGEST_SIZE, STREEBOG256_BLOCK_SIZE); EG(ret, err); 174 175 ctx->magic = STREEBOG256_HASH_MAGIC; 176 177 err: 178 return ret; 179 } 180 181 /* Update */ 182 int streebog256_update(streebog256_context *ctx, const u8 *input, u32 ilen) 183 { 184 int ret; 185 186 STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err); 187 188 ret = streebog_update(ctx, input, ilen); 189 190 err: 191 return ret; 192 } 193 194 /* Finalize */ 195 int streebog256_final(streebog256_context *ctx, 196 u8 output[STREEBOG256_DIGEST_SIZE]) 197 { 198 int ret; 199 200 STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err); 201 202 ret = streebog_final(ctx, output); EG(ret, err); 203 204 /* Uninit our context magic */ 205 ctx->magic = WORD(0); 206 207 ret = 0; 208 209 err: 210 return ret; 211 } 212 213 int streebog256_scattered(const u8 **inputs, const u32 *ilens, 214 u8 output[STREEBOG256_DIGEST_SIZE]) 215 { 216 streebog256_context ctx; 217 int pos = 0; 218 int ret; 219 220 MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err); 221 222 ret = streebog256_init(&ctx); EG(ret, err); 223 224 while (inputs[pos] != NULL) { 225 ret = streebog256_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err); 226 pos += 1; 227 } 228 229 ret = streebog256_final(&ctx, output); 230 231 err: 232 return ret; 233 } 234 235 int streebog256(const u8 *input, u32 ilen, u8 output[STREEBOG256_DIGEST_SIZE]) 236 { 237 int ret; 238 streebog256_context ctx; 239 240 ret = streebog256_init(&ctx); EG(ret, err); 241 ret = streebog256_update(&ctx, input, ilen); EG(ret, err); 242 ret = streebog256_final(&ctx, output); 243 244 err: 245 return ret; 246 } 247 248 #endif /* defined(WITH_HASH_STREEBOG256) */ 249 250 251 #if defined(WITH_HASH_STREEBOG512) 252 253 /* Init */ 254 int streebog512_init(streebog512_context *ctx) 255 { 256 int ret; 257 258 ret = streebog_init(ctx, STREEBOG512_DIGEST_SIZE, STREEBOG512_BLOCK_SIZE); EG(ret, err); 259 260 ctx->magic = STREEBOG512_HASH_MAGIC; 261 262 ret = 0; 263 264 err: 265 return ret; 266 } 267 268 /* Update */ 269 int streebog512_update(streebog512_context *ctx, const u8 *input, u32 ilen) 270 { 271 int ret; 272 273 STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err); 274 275 ret = streebog_update(ctx, input, ilen); 276 277 err: 278 return ret; 279 } 280 281 /* Finalize */ 282 int streebog512_final(streebog512_context *ctx, 283 u8 output[STREEBOG512_DIGEST_SIZE]) 284 { 285 int ret; 286 287 STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err); 288 289 ret = streebog_final(ctx, output); EG(ret, err); 290 291 /* Uninit our context magic */ 292 ctx->magic = WORD(0); 293 294 ret = 0; 295 296 err: 297 return ret; 298 } 299 300 int streebog512_scattered(const u8 **inputs, const u32 *ilens, 301 u8 output[STREEBOG512_DIGEST_SIZE]) 302 { 303 streebog512_context ctx; 304 int pos = 0; 305 int ret; 306 307 MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err); 308 309 ret = streebog512_init(&ctx); EG(ret, err); 310 311 while (inputs[pos] != NULL) { 312 ret = streebog512_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err); 313 pos += 1; 314 } 315 316 ret = streebog512_final(&ctx, output); 317 318 err: 319 return ret; 320 } 321 322 int streebog512(const u8 *input, u32 ilen, u8 output[STREEBOG512_DIGEST_SIZE]) 323 { 324 int ret; 325 streebog512_context ctx; 326 327 ret = streebog512_init(&ctx); EG(ret, err); 328 ret = streebog512_update(&ctx, input, ilen); EG(ret, err); 329 ret = streebog512_final(&ctx, output); 330 331 err: 332 return ret; 333 } 334 335 #endif /* defined(WITH_HASH_STREEBOG512) */ 336 337 #else /* !(defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)) */ 338 /* 339 * Dummy definition to avoid the empty translation unit ISO C warning 340 */ 341 typedef int dummy; 342 343 #endif /* defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512) */ 344 345