1 /* 2 BLAKE2 reference source code package - C implementations 3 4 Written in 2012 by Samuel Neves <sneves@dei.uc.pt> 5 6 To the extent possible under law, the author(s) have dedicated all copyright 7 and related and neighboring rights to this software to the public domain 8 worldwide. This software is distributed without any warranty. 9 10 You should have received a copy of the CC0 Public Domain Dedication along 11 with 12 this software. If not, see 13 <http://creativecommons.org/publicdomain/zero/1.0/>. 14 */ 15 16 #include <assert.h> 17 #include <stddef.h> 18 #include <stdint.h> 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include "blake2.h" 23 #include "core.h" 24 #include "private/common.h" 25 #include "runtime.h" 26 #include "utils.h" 27 28 static blake2b_compress_fn blake2b_compress = blake2b_compress_ref; 29 30 static const uint64_t blake2b_IV[8] = { 31 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 32 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 33 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL 34 }; 35 36 /* LCOV_EXCL_START */ 37 static inline int 38 blake2b_set_lastnode(blake2b_state *S) 39 { 40 S->f[1] = -1; 41 return 0; 42 } 43 /* LCOV_EXCL_STOP */ 44 45 static inline int 46 blake2b_is_lastblock(const blake2b_state *S) 47 { 48 return S->f[0] != 0; 49 } 50 51 static inline int 52 blake2b_set_lastblock(blake2b_state *S) 53 { 54 if (S->last_node) { 55 blake2b_set_lastnode(S); 56 } 57 S->f[0] = -1; 58 return 0; 59 } 60 61 static inline int 62 blake2b_increment_counter(blake2b_state *S, const uint64_t inc) 63 { 64 #ifdef HAVE_TI_MODE 65 uint128_t t = ((uint128_t) S->t[1] << 64) | S->t[0]; 66 t += inc; 67 S->t[0] = (uint64_t)(t >> 0); 68 S->t[1] = (uint64_t)(t >> 64); 69 #else 70 S->t[0] += inc; 71 S->t[1] += (S->t[0] < inc); 72 #endif 73 return 0; 74 } 75 76 /* Parameter-related functions */ 77 static inline int 78 blake2b_param_set_salt(blake2b_param *P, const uint8_t salt[BLAKE2B_SALTBYTES]) 79 { 80 memcpy(P->salt, salt, BLAKE2B_SALTBYTES); 81 return 0; 82 } 83 84 static inline int 85 blake2b_param_set_personal(blake2b_param *P, 86 const uint8_t personal[BLAKE2B_PERSONALBYTES]) 87 { 88 memcpy(P->personal, personal, BLAKE2B_PERSONALBYTES); 89 return 0; 90 } 91 92 static inline int 93 blake2b_init0(blake2b_state *S) 94 { 95 int i; 96 97 for (i = 0; i < 8; i++) { 98 S->h[i] = blake2b_IV[i]; 99 } 100 memset(S->t, 0, offsetof(blake2b_state, last_node) + sizeof(S->last_node) 101 - offsetof(blake2b_state, t)); 102 return 0; 103 } 104 105 /* init xors IV with input parameter block */ 106 int 107 blake2b_init_param(blake2b_state *S, const blake2b_param *P) 108 { 109 size_t i; 110 const uint8_t *p; 111 112 COMPILER_ASSERT(sizeof *P == 64); 113 blake2b_init0(S); 114 p = (const uint8_t *) (P); 115 116 /* IV XOR ParamBlock */ 117 for (i = 0; i < 8; i++) { 118 S->h[i] ^= LOAD64_LE(p + sizeof(S->h[i]) * i); 119 } 120 return 0; 121 } 122 123 int 124 blake2b_init(blake2b_state *S, const uint8_t outlen) 125 { 126 blake2b_param P[1]; 127 128 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { 129 sodium_misuse(); 130 } 131 P->digest_length = outlen; 132 P->key_length = 0; 133 P->fanout = 1; 134 P->depth = 1; 135 STORE32_LE(P->leaf_length, 0); 136 STORE64_LE(P->node_offset, 0); 137 P->node_depth = 0; 138 P->inner_length = 0; 139 memset(P->reserved, 0, sizeof(P->reserved)); 140 memset(P->salt, 0, sizeof(P->salt)); 141 memset(P->personal, 0, sizeof(P->personal)); 142 return blake2b_init_param(S, P); 143 } 144 145 int 146 blake2b_init_salt_personal(blake2b_state *S, const uint8_t outlen, 147 const void *salt, const void *personal) 148 { 149 blake2b_param P[1]; 150 151 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { 152 sodium_misuse(); 153 } 154 P->digest_length = outlen; 155 P->key_length = 0; 156 P->fanout = 1; 157 P->depth = 1; 158 STORE32_LE(P->leaf_length, 0); 159 STORE64_LE(P->node_offset, 0); 160 P->node_depth = 0; 161 P->inner_length = 0; 162 memset(P->reserved, 0, sizeof(P->reserved)); 163 if (salt != NULL) { 164 blake2b_param_set_salt(P, (const uint8_t *) salt); 165 } else { 166 memset(P->salt, 0, sizeof(P->salt)); 167 } 168 if (personal != NULL) { 169 blake2b_param_set_personal(P, (const uint8_t *) personal); 170 } else { 171 memset(P->personal, 0, sizeof(P->personal)); 172 } 173 return blake2b_init_param(S, P); 174 } 175 176 int 177 blake2b_init_key(blake2b_state *S, const uint8_t outlen, const void *key, 178 const uint8_t keylen) 179 { 180 blake2b_param P[1]; 181 182 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { 183 sodium_misuse(); 184 } 185 if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) { 186 sodium_misuse(); 187 } 188 P->digest_length = outlen; 189 P->key_length = keylen; 190 P->fanout = 1; 191 P->depth = 1; 192 STORE32_LE(P->leaf_length, 0); 193 STORE64_LE(P->node_offset, 0); 194 P->node_depth = 0; 195 P->inner_length = 0; 196 memset(P->reserved, 0, sizeof(P->reserved)); 197 memset(P->salt, 0, sizeof(P->salt)); 198 memset(P->personal, 0, sizeof(P->personal)); 199 200 if (blake2b_init_param(S, P) < 0) { 201 sodium_misuse(); 202 } 203 { 204 uint8_t block[BLAKE2B_BLOCKBYTES]; 205 memset(block, 0, BLAKE2B_BLOCKBYTES); 206 memcpy(block, key, keylen); /* keylen cannot be 0 */ 207 blake2b_update(S, block, BLAKE2B_BLOCKBYTES); 208 sodium_memzero(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ 209 } 210 return 0; 211 } 212 213 int 214 blake2b_init_key_salt_personal(blake2b_state *S, const uint8_t outlen, 215 const void *key, const uint8_t keylen, 216 const void *salt, const void *personal) 217 { 218 blake2b_param P[1]; 219 220 if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { 221 sodium_misuse(); 222 } 223 if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) { 224 sodium_misuse(); 225 } 226 P->digest_length = outlen; 227 P->key_length = keylen; 228 P->fanout = 1; 229 P->depth = 1; 230 STORE32_LE(P->leaf_length, 0); 231 STORE64_LE(P->node_offset, 0); 232 P->node_depth = 0; 233 P->inner_length = 0; 234 memset(P->reserved, 0, sizeof(P->reserved)); 235 if (salt != NULL) { 236 blake2b_param_set_salt(P, (const uint8_t *) salt); 237 } else { 238 memset(P->salt, 0, sizeof(P->salt)); 239 } 240 if (personal != NULL) { 241 blake2b_param_set_personal(P, (const uint8_t *) personal); 242 } else { 243 memset(P->personal, 0, sizeof(P->personal)); 244 } 245 246 if (blake2b_init_param(S, P) < 0) { 247 sodium_misuse(); 248 } 249 { 250 uint8_t block[BLAKE2B_BLOCKBYTES]; 251 memset(block, 0, BLAKE2B_BLOCKBYTES); 252 memcpy(block, key, keylen); /* keylen cannot be 0 */ 253 blake2b_update(S, block, BLAKE2B_BLOCKBYTES); 254 sodium_memzero(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ 255 } 256 return 0; 257 } 258 259 /* inlen now in bytes */ 260 int 261 blake2b_update(blake2b_state *S, const uint8_t *in, uint64_t inlen) 262 { 263 while (inlen > 0) { 264 size_t left = S->buflen; 265 size_t fill = 2 * BLAKE2B_BLOCKBYTES - left; 266 267 if (inlen > fill) { 268 memcpy(S->buf + left, in, fill); /* Fill buffer */ 269 S->buflen += fill; 270 blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); 271 blake2b_compress(S, S->buf); /* Compress */ 272 memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, 273 BLAKE2B_BLOCKBYTES); /* Shift buffer left */ 274 S->buflen -= BLAKE2B_BLOCKBYTES; 275 in += fill; 276 inlen -= fill; 277 } else /* inlen <= fill */ 278 { 279 memcpy(S->buf + left, in, inlen); 280 S->buflen += inlen; /* Be lazy, do not compress */ 281 in += inlen; 282 inlen -= inlen; 283 } 284 } 285 286 return 0; 287 } 288 289 int 290 blake2b_final(blake2b_state *S, uint8_t *out, uint8_t outlen) 291 { 292 unsigned char buffer[BLAKE2B_OUTBYTES]; 293 294 if (!outlen || outlen > BLAKE2B_OUTBYTES) { 295 sodium_misuse(); 296 } 297 if (blake2b_is_lastblock(S)) { 298 return -1; 299 } 300 if (S->buflen > BLAKE2B_BLOCKBYTES) { 301 blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); 302 blake2b_compress(S, S->buf); 303 S->buflen -= BLAKE2B_BLOCKBYTES; 304 assert(S->buflen <= BLAKE2B_BLOCKBYTES); 305 memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen); 306 } 307 308 blake2b_increment_counter(S, S->buflen); 309 blake2b_set_lastblock(S); 310 memset(S->buf + S->buflen, 0, 311 2 * BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ 312 blake2b_compress(S, S->buf); 313 314 COMPILER_ASSERT(sizeof buffer == 64U); 315 STORE64_LE(buffer + 8 * 0, S->h[0]); 316 STORE64_LE(buffer + 8 * 1, S->h[1]); 317 STORE64_LE(buffer + 8 * 2, S->h[2]); 318 STORE64_LE(buffer + 8 * 3, S->h[3]); 319 STORE64_LE(buffer + 8 * 4, S->h[4]); 320 STORE64_LE(buffer + 8 * 5, S->h[5]); 321 STORE64_LE(buffer + 8 * 6, S->h[6]); 322 STORE64_LE(buffer + 8 * 7, S->h[7]); 323 memcpy(out, buffer, outlen); /* outlen <= BLAKE2B_OUTBYTES (64) */ 324 325 sodium_memzero(S->h, sizeof S->h); 326 sodium_memzero(S->buf, sizeof S->buf); 327 328 return 0; 329 } 330 331 /* inlen, at least, should be uint64_t. Others can be size_t. */ 332 int 333 blake2b(uint8_t *out, const void *in, const void *key, const uint8_t outlen, 334 const uint64_t inlen, uint8_t keylen) 335 { 336 CRYPTO_ALIGN(64) blake2b_state S[1]; 337 338 /* Verify parameters */ 339 if (NULL == in && inlen > 0) { 340 sodium_misuse(); 341 } 342 if (NULL == out) { 343 sodium_misuse(); 344 } 345 if (!outlen || outlen > BLAKE2B_OUTBYTES) { 346 sodium_misuse(); 347 } 348 if (NULL == key && keylen > 0) { 349 sodium_misuse(); 350 } 351 if (keylen > BLAKE2B_KEYBYTES) { 352 sodium_misuse(); 353 } 354 if (keylen > 0) { 355 if (blake2b_init_key(S, outlen, key, keylen) < 0) { 356 sodium_misuse(); 357 } 358 } else { 359 if (blake2b_init(S, outlen) < 0) { 360 sodium_misuse(); 361 } 362 } 363 364 blake2b_update(S, (const uint8_t *) in, inlen); 365 blake2b_final(S, out, outlen); 366 return 0; 367 } 368 369 int 370 blake2b_salt_personal(uint8_t *out, const void *in, const void *key, 371 const uint8_t outlen, const uint64_t inlen, 372 uint8_t keylen, const void *salt, const void *personal) 373 { 374 CRYPTO_ALIGN(64) blake2b_state S[1]; 375 376 /* Verify parameters */ 377 if (NULL == in && inlen > 0) { 378 sodium_misuse(); 379 } 380 if (NULL == out) { 381 sodium_misuse(); 382 } 383 if (!outlen || outlen > BLAKE2B_OUTBYTES) { 384 sodium_misuse(); 385 } 386 if (NULL == key && keylen > 0) { 387 sodium_misuse(); 388 } 389 if (keylen > BLAKE2B_KEYBYTES) { 390 sodium_misuse(); 391 } 392 if (keylen > 0) { 393 if (blake2b_init_key_salt_personal(S, outlen, key, keylen, salt, 394 personal) < 0) { 395 sodium_misuse(); 396 } 397 } else { 398 if (blake2b_init_salt_personal(S, outlen, salt, personal) < 0) { 399 sodium_misuse(); 400 } 401 } 402 403 blake2b_update(S, (const uint8_t *) in, inlen); 404 blake2b_final(S, out, outlen); 405 return 0; 406 } 407 408 int 409 blake2b_pick_best_implementation(void) 410 { 411 /* LCOV_EXCL_START */ 412 #if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ 413 defined(HAVE_SMMINTRIN_H) 414 if (sodium_runtime_has_avx2()) { 415 blake2b_compress = blake2b_compress_avx2; 416 return 0; 417 } 418 #endif 419 #if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ 420 defined(HAVE_SMMINTRIN_H) 421 if (sodium_runtime_has_sse41()) { 422 blake2b_compress = blake2b_compress_sse41; 423 return 0; 424 } 425 #endif 426 #if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) 427 if (sodium_runtime_has_ssse3()) { 428 blake2b_compress = blake2b_compress_ssse3; 429 return 0; 430 } 431 #endif 432 blake2b_compress = blake2b_compress_ref; 433 434 return 0; 435 /* LCOV_EXCL_STOP */ 436 } 437