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 #include <libecc/lib_ecc_config.h> 12 #ifdef WITH_HASH_BELT_HASH 13 14 #include <libecc/hash/belt-hash.h> 15 16 /* 17 * This is an implementation of the BELT-HASH hash function as 18 * defined int STB 34.101.31. 19 */ 20 21 22 /* 23 * The BELT-HASH function uses an underlying BELT block cipher 24 * defined in STB 34.101.31. This is a simple and straitforward 25 * implementation. 26 */ 27 #define ROTL_BELT(x, n) ((((u32)(x)) << (n)) | (((u32)(x)) >> (32-(n)))) 28 29 #define SWAP_BELT(x, y) do { \ 30 u32 z; \ 31 z = (x); \ 32 (x) = (y); \ 33 (y) = z; \ 34 } while(0) 35 36 /* The S-Box */ 37 static u8 S[256] = 38 { 39 0xB1, 0x94, 0xBA, 0xC8, 0x0A, 0x08, 0xF5, 0x3B, 0x36, 0x6D, 0x00, 0x8E, 0x58, 0x4A, 0x5D, 0xE4, 40 0x85, 0x04, 0xFA, 0x9D, 0x1B, 0xB6, 0xC7, 0xAC, 0x25, 0x2E, 0x72, 0xC2, 0x02, 0xFD, 0xCE, 0x0D, 41 0x5B, 0xE3, 0xD6, 0x12, 0x17, 0xB9, 0x61, 0x81, 0xFE, 0x67, 0x86, 0xAD, 0x71, 0x6B, 0x89, 0x0B, 42 0x5C, 0xB0, 0xC0, 0xFF, 0x33, 0xC3, 0x56, 0xB8, 0x35, 0xC4, 0x05, 0xAE, 0xD8, 0xE0, 0x7F, 0x99, 43 0xE1, 0x2B, 0xDC, 0x1A, 0xE2, 0x82, 0x57, 0xEC, 0x70, 0x3F, 0xCC, 0xF0, 0x95, 0xEE, 0x8D, 0xF1, 44 0xC1, 0xAB, 0x76, 0x38, 0x9F, 0xE6, 0x78, 0xCA, 0xF7, 0xC6, 0xF8, 0x60, 0xD5, 0xBB, 0x9C, 0x4F, 45 0xF3, 0x3C, 0x65, 0x7B, 0x63, 0x7C, 0x30, 0x6A, 0xDD, 0x4E, 0xA7, 0x79, 0x9E, 0xB2, 0x3D, 0x31, 46 0x3E, 0x98, 0xB5, 0x6E, 0x27, 0xD3, 0xBC, 0xCF, 0x59, 0x1E, 0x18, 0x1F, 0x4C, 0x5A, 0xB7, 0x93, 47 0xE9, 0xDE, 0xE7, 0x2C, 0x8F, 0x0C, 0x0F, 0xA6, 0x2D, 0xDB, 0x49, 0xF4, 0x6F, 0x73, 0x96, 0x47, 48 0x06, 0x07, 0x53, 0x16, 0xED, 0x24, 0x7A, 0x37, 0x39, 0xCB, 0xA3, 0x83, 0x03, 0xA9, 0x8B, 0xF6, 49 0x92, 0xBD, 0x9B, 0x1C, 0xE5, 0xD1, 0x41, 0x01, 0x54, 0x45, 0xFB, 0xC9, 0x5E, 0x4D, 0x0E, 0xF2, 50 0x68, 0x20, 0x80, 0xAA, 0x22, 0x7D, 0x64, 0x2F, 0x26, 0x87, 0xF9, 0x34, 0x90, 0x40, 0x55, 0x11, 51 0xBE, 0x32, 0x97, 0x13, 0x43, 0xFC, 0x9A, 0x48, 0xA0, 0x2A, 0x88, 0x5F, 0x19, 0x4B, 0x09, 0xA1, 52 0x7E, 0xCD, 0xA4, 0xD0, 0x15, 0x44, 0xAF, 0x8C, 0xA5, 0x84, 0x50, 0xBF, 0x66, 0xD2, 0xE8, 0x8A, 53 0xA2, 0xD7, 0x46, 0x52, 0x42, 0xA8, 0xDF, 0xB3, 0x69, 0x74, 0xC5, 0x51, 0xEB, 0x23, 0x29, 0x21, 54 0xD4, 0xEF, 0xD9, 0xB4, 0x3A, 0x62, 0x28, 0x75, 0x91, 0x14, 0x10, 0xEA, 0x77, 0x6C, 0xDA, 0x1D, 55 }; 56 57 /* */ 58 #define GET_BYTE(x, a) ( ((x) >> (a)) & 0xff ) 59 #define PUT_BYTE(x, a) ( (u32)(x) << (a) ) 60 #define SB(x, a) PUT_BYTE( S[GET_BYTE((x), (a))], (a) ) 61 62 #define G(x, r) ROTL_BELT( SB((x), 24) | SB((x), 16) | SB((x), 8) | SB((x), 0), (r) ) 63 64 static u32 KIdx[8][7] = 65 { 66 { 0, 1, 2, 3, 4, 5, 6 }, 67 { 7, 0, 1, 2, 3, 4, 5 }, 68 { 6, 7, 0, 1, 2, 3, 4 }, 69 { 5, 6, 7, 0, 1, 2, 3 }, 70 { 4, 5, 6, 7, 0, 1, 2 }, 71 { 3, 4, 5, 6, 7, 0, 1 }, 72 { 2, 3, 4, 5, 6, 7, 0 }, 73 { 1, 2, 3, 4, 5, 6, 7 }, 74 }; 75 76 int belt_init(const u8 *k, u32 k_len, u8 ks[BELT_KEY_SCHED_LEN]) 77 { 78 int ret = -1; 79 unsigned int i; 80 81 switch(k_len){ 82 case 16:{ 83 for(i = 0; i < 16; i++){ 84 ks[i] = k[i]; 85 ks[i + 16] = k[i]; 86 } 87 break; 88 } 89 case 24:{ 90 for(i = 0; i < 24; i++){ 91 ks[i] = k[i]; 92 } 93 for(i = 24; i < 32; i++){ 94 ks[i] = k[i - 24] ^ k[i - 20] ^ k[i - 16]; 95 } 96 break; 97 } 98 case 32:{ 99 for(i = 0; i < 32; i++){ 100 ks[i] = k[i]; 101 } 102 break; 103 } 104 default:{ 105 ret = -1; 106 goto err; 107 } 108 109 110 } 111 112 ret = 0; 113 err: 114 return ret; 115 } 116 117 void belt_encrypt(const u8 in[BELT_BLOCK_LEN], u8 out[BELT_BLOCK_LEN], const u8 ks[BELT_KEY_SCHED_LEN]) 118 { 119 u32 a, b, c, d, e; 120 u32 i; 121 122 GET_UINT32_LE(a, in, 0); 123 GET_UINT32_LE(b, in, 4); 124 GET_UINT32_LE(c, in, 8); 125 GET_UINT32_LE(d, in, 12); 126 127 for(i = 0; i < 8; i++){ 128 u32 key; 129 GET_UINT32_LE(key, ks, 4*KIdx[i][0]); 130 b ^= G(a + key, 5); 131 GET_UINT32_LE(key, ks, 4*KIdx[i][1]); 132 c ^= G(d + key, 21); 133 GET_UINT32_LE(key, ks, 4*KIdx[i][2]); 134 a = (u32)(a - G(b + key, 13)); 135 GET_UINT32_LE(key, ks, 4*KIdx[i][3]); 136 e = G(b + c + key, 21) ^ (i + 1); 137 b += e; 138 c = (u32)(c - e); 139 GET_UINT32_LE(key, ks, 4*KIdx[i][4]); 140 d += G(c + key, 13); 141 GET_UINT32_LE(key, ks, 4*KIdx[i][5]); 142 b ^= G(a + key, 21); 143 GET_UINT32_LE(key, ks, 4*KIdx[i][6]); 144 c ^= G(d + key, 5); 145 SWAP_BELT(a, b); 146 SWAP_BELT(c, d); 147 SWAP_BELT(b, c); 148 } 149 150 PUT_UINT32_LE(b, out, 0); 151 PUT_UINT32_LE(d, out, 4); 152 PUT_UINT32_LE(a, out, 8); 153 PUT_UINT32_LE(c, out, 12); 154 155 return; 156 } 157 158 void belt_decrypt(const u8 in[BELT_BLOCK_LEN], u8 out[BELT_BLOCK_LEN], const u8 ks[BELT_KEY_SCHED_LEN]) 159 { 160 u32 a, b, c, d, e; 161 u32 i; 162 163 GET_UINT32_LE(a, in, 0); 164 GET_UINT32_LE(b, in, 4); 165 GET_UINT32_LE(c, in, 8); 166 GET_UINT32_LE(d, in, 12); 167 168 for(i = 0; i < 8; i++){ 169 u32 key; 170 u32 j = (7 - i); 171 GET_UINT32_LE(key, ks, 4*KIdx[i][6]); 172 b ^= G(a + key, 5); 173 GET_UINT32_LE(key, ks, 4*KIdx[i][5]); 174 c ^= G(d + key, 21); 175 GET_UINT32_LE(key, ks, 4*KIdx[i][4]); 176 a = (u32)(a - G(b + key, 13)); 177 GET_UINT32_LE(key, ks, 4*KIdx[i][3]); 178 e = G(b + c + key, 21) ^ (j + 1); 179 b += e; 180 c = (u32)(c - e); 181 GET_UINT32_LE(key, ks, 4*KIdx[i][2]); 182 d += G(c + key, 13); 183 GET_UINT32_LE(key, ks, 4*KIdx[i][1]); 184 b ^= G(a + key, 21); 185 GET_UINT32_LE(key, ks, 4*KIdx[i][0]); 186 c ^= G(d + key, 5); 187 SWAP_BELT(a, b); 188 SWAP_BELT(c, d); 189 SWAP_BELT(a, d); 190 } 191 192 PUT_UINT32_LE(c, out, 0); 193 PUT_UINT32_LE(a, out, 4); 194 PUT_UINT32_LE(d, out, 8); 195 PUT_UINT32_LE(b, out, 12); 196 197 return; 198 } 199 200 /* BELT-HASH primitives */ 201 static void sigma1_xor(const u8 x[2 * BELT_BLOCK_LEN], const u8 h[2 * BELT_BLOCK_LEN], u8 s[BELT_BLOCK_LEN], u8 use_xor){ 202 u8 tmp1[BELT_BLOCK_LEN]; 203 unsigned int i; 204 205 for(i = 0; i < (BELT_BLOCK_LEN / 2); i++){ 206 tmp1[i] = (h[i] ^ h[i + BELT_BLOCK_LEN]); 207 tmp1[i + (BELT_BLOCK_LEN / 2)] = (h[i + (BELT_BLOCK_LEN / 2)] ^ h[i + BELT_BLOCK_LEN + (BELT_BLOCK_LEN / 2)]); 208 } 209 210 if(use_xor){ 211 u8 tmp2[BELT_BLOCK_LEN]; 212 213 belt_encrypt(tmp1, tmp2, x); 214 215 for(i = 0; i < (BELT_BLOCK_LEN / 2); i++){ 216 s[i] ^= (tmp1[i] ^ tmp2[i]); 217 s[i + (BELT_BLOCK_LEN / 2)] ^= (tmp1[i + (BELT_BLOCK_LEN / 2)] ^ tmp2[i + (BELT_BLOCK_LEN / 2)]); 218 } 219 } 220 else{ 221 belt_encrypt(tmp1, s, x); 222 for(i = 0; i < (BELT_BLOCK_LEN / 2); i++){ 223 s[i] ^= tmp1[i]; 224 s[i + (BELT_BLOCK_LEN / 2)] ^= tmp1[i + (BELT_BLOCK_LEN / 2)]; 225 } 226 } 227 228 return; 229 } 230 231 static void sigma2(const u8 x[2 * BELT_BLOCK_LEN], u8 const h[2 * BELT_BLOCK_LEN], u8 result[2 * BELT_BLOCK_LEN]) 232 { 233 u8 teta[BELT_KEY_SCHED_LEN]; 234 u8 tmp[BELT_BLOCK_LEN]; 235 unsigned int i; 236 237 /* Copy the beginning of h for later in case it is lost */ 238 IGNORE_RET_VAL(local_memcpy(&tmp[0], &h[0], BELT_BLOCK_LEN)); 239 240 sigma1_xor(x, h, teta, 0); 241 IGNORE_RET_VAL(local_memcpy(&teta[BELT_BLOCK_LEN], &h[BELT_BLOCK_LEN], BELT_BLOCK_LEN)); 242 243 belt_encrypt(x, result, teta); 244 for(i = 0; i < BELT_BLOCK_LEN; i++){ 245 result[i] ^= x[i]; 246 teta[i] ^= 0xff; 247 teta[i + BELT_BLOCK_LEN] = tmp[i]; 248 } 249 250 belt_encrypt(&x[BELT_BLOCK_LEN], &result[BELT_BLOCK_LEN], teta); 251 252 for(i = 0; i < (BELT_BLOCK_LEN / 2); i++){ 253 result[i + BELT_BLOCK_LEN] ^= x[i + BELT_BLOCK_LEN]; 254 result[i + BELT_BLOCK_LEN + (BELT_BLOCK_LEN / 2)] ^= x[i + BELT_BLOCK_LEN + (BELT_BLOCK_LEN / 2)]; 255 } 256 257 return; 258 } 259 260 static void _belt_hash_process(const u8 x[2 * BELT_BLOCK_LEN], u8 h[2 * BELT_BLOCK_LEN], u8 s[BELT_BLOCK_LEN]) 261 { 262 sigma1_xor(x, h, s, 1); 263 264 sigma2(x, h, h); 265 266 return; 267 } 268 269 ATTRIBUTE_WARN_UNUSED_RET static int belt_hash_process(belt_hash_context *ctx, const u8 data[BELT_HASH_BLOCK_SIZE]) 270 { 271 _belt_hash_process(data, ctx->belt_hash_h, &(ctx->belt_hash_state[BELT_BLOCK_LEN])); 272 273 return 0; 274 } 275 276 ATTRIBUTE_WARN_UNUSED_RET static int belt_hash_finalize(const u8 s[2 * BELT_BLOCK_LEN], const u8 h[2 * BELT_BLOCK_LEN], u8 res[2 * BELT_BLOCK_LEN]) 277 { 278 sigma2(s, h, res); 279 280 return 0; 281 } 282 283 static void belt_update_ctr(belt_hash_context *ctx, u8 len_bytes) 284 { 285 /* Perform a simple addition on 128 bits on the first part of the state */ 286 u64 a0, a1, b, c; 287 288 GET_UINT64_LE(a0, (const u8*)(ctx->belt_hash_state), 0); 289 GET_UINT64_LE(a1, (const u8*)(ctx->belt_hash_state), 8); 290 291 b = (u64)(len_bytes << 3); 292 293 c = (a0 + b); 294 if(c < b){ 295 /* Handle carry */ 296 a1 += 1; 297 } 298 299 /* Store the result */ 300 PUT_UINT64_LE(c, (u8*)(ctx->belt_hash_state), 0); 301 PUT_UINT64_LE(a1, (u8*)(ctx->belt_hash_state), 8); 302 303 return; 304 } 305 306 /* Init hash function. Returns 0 on success, -1 on error. */ 307 int belt_hash_init(belt_hash_context *ctx) 308 { 309 int ret; 310 311 MUST_HAVE((ctx != NULL), ret, err); 312 313 ctx->belt_hash_total = 0; 314 315 ret = local_memset(ctx->belt_hash_state, 0, sizeof(ctx->belt_hash_state)); EG(ret, err); 316 317 PUT_UINT64_LE(0x3bf5080ac8ba94b1ULL, ctx->belt_hash_h, 0); 318 PUT_UINT64_LE(0xe45d4a588e006d36ULL, ctx->belt_hash_h, 8); 319 PUT_UINT64_LE(0xacc7b61b9dfa0485ULL, ctx->belt_hash_h, 16); 320 PUT_UINT64_LE(0x0dcefd02c2722e25ULL, ctx->belt_hash_h, 24); 321 322 /* Tell that we are initialized */ 323 ctx->magic = BELT_HASH_HASH_MAGIC; 324 325 ret = 0; 326 327 err: 328 return ret; 329 } 330 331 /* Update hash function. Returns 0 on success, -1 on error. */ 332 int belt_hash_update(belt_hash_context *ctx, const u8 *input, u32 ilen) 333 { 334 const u8 *data_ptr = input; 335 u32 remain_ilen = ilen; 336 u16 fill; 337 u8 left; 338 int ret; 339 340 MUST_HAVE((input != NULL) || (ilen == 0), ret, err); 341 BELT_HASH_HASH_CHECK_INITIALIZED(ctx, ret, err); 342 343 /* Nothing to process, return */ 344 if (ilen == 0) { 345 ret = 0; 346 goto err; 347 } 348 349 /* Get what's left in our local buffer */ 350 left = (ctx->belt_hash_total & (BELT_HASH_BLOCK_SIZE - 1)); 351 fill = (u16)(BELT_HASH_BLOCK_SIZE - left); 352 353 ctx->belt_hash_total += ilen; 354 355 if ((left > 0) && (remain_ilen >= fill)) { 356 /* Copy data at the end of the buffer */ 357 ret = local_memcpy(ctx->belt_hash_buffer + left, data_ptr, fill); EG(ret, err); 358 /* Update the counter with one full block */ 359 belt_update_ctr(ctx, BELT_HASH_BLOCK_SIZE); 360 /* Process */ 361 ret = belt_hash_process(ctx, ctx->belt_hash_buffer); EG(ret, err); 362 data_ptr += fill; 363 remain_ilen -= fill; 364 left = 0; 365 } 366 367 while (remain_ilen >= BELT_HASH_BLOCK_SIZE) { 368 /* Update the counter with one full block */ 369 belt_update_ctr(ctx, BELT_HASH_BLOCK_SIZE); 370 /* Process */ 371 ret = belt_hash_process(ctx, data_ptr); EG(ret, err); 372 data_ptr += BELT_HASH_BLOCK_SIZE; 373 remain_ilen -= BELT_HASH_BLOCK_SIZE; 374 } 375 376 if (remain_ilen > 0) { 377 ret = local_memcpy(ctx->belt_hash_buffer + left, data_ptr, remain_ilen); EG(ret, err); 378 } 379 380 ret = 0; 381 382 err: 383 return ret; 384 } 385 386 /* Finalize. Returns 0 on success, -1 on error.*/ 387 int belt_hash_final(belt_hash_context *ctx, u8 output[BELT_HASH_DIGEST_SIZE]) 388 { 389 int ret; 390 unsigned int i; 391 392 MUST_HAVE((output != NULL), ret, err); 393 BELT_HASH_HASH_CHECK_INITIALIZED(ctx, ret, err); 394 395 if((ctx->belt_hash_total % BELT_HASH_BLOCK_SIZE) != 0){ 396 /* Pad our last block with zeroes */ 397 for(i = (ctx->belt_hash_total % BELT_HASH_BLOCK_SIZE); i < BELT_HASH_BLOCK_SIZE; i++){ 398 ctx->belt_hash_buffer[i] = 0; 399 } 400 401 /* Update the counter with the remaining data */ 402 belt_update_ctr(ctx, (u8)(ctx->belt_hash_total % BELT_HASH_BLOCK_SIZE)); 403 404 /* Process the last block */ 405 ret = belt_hash_process(ctx, ctx->belt_hash_buffer); EG(ret, err); 406 } 407 408 /* Finalize and output the result */ 409 ret = belt_hash_finalize(ctx->belt_hash_state, ctx->belt_hash_h, output); EG(ret, err); 410 411 /* Tell that we are uninitialized */ 412 ctx->magic = WORD(0); 413 414 ret = 0; 415 416 err: 417 return ret; 418 } 419 420 /* 421 * Scattered version performing init/update/finalize on a vector of buffers 422 * 'inputs' with the length of each buffer passed via 'ilens'. The function 423 * loops on pointers in 'inputs' until it finds a NULL pointer. The function 424 * returns 0 on success, -1 on error. 425 */ 426 int belt_hash_scattered(const u8 **inputs, const u32 *ilens, 427 u8 output[BELT_HASH_DIGEST_SIZE]) 428 { 429 belt_hash_context ctx; 430 int ret, pos = 0; 431 432 MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err); 433 434 ret = belt_hash_init(&ctx); EG(ret, err); 435 436 while (inputs[pos] != NULL) { 437 ret = belt_hash_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err); 438 pos += 1; 439 } 440 441 ret = belt_hash_final(&ctx, output); 442 443 err: 444 return ret; 445 } 446 447 /* 448 * Single call version performing init/update/final on given input. 449 * Returns 0 on success, -1 on error. 450 */ 451 int belt_hash(const u8 *input, u32 ilen, u8 output[BELT_HASH_DIGEST_SIZE]) 452 { 453 belt_hash_context ctx; 454 int ret; 455 456 ret = belt_hash_init(&ctx); EG(ret, err); 457 ret = belt_hash_update(&ctx, input, ilen); EG(ret, err); 458 ret = belt_hash_final(&ctx, output); 459 460 err: 461 return ret; 462 } 463 464 #else /* WITH_HASH_BELT_HASH */ 465 466 /* 467 * Dummy definition to avoid the empty translation unit ISO C warning 468 */ 469 typedef int dummy; 470 471 #endif /* WITH_HASH_BELT_HASH */ 472