1 /*
2 BLAKE2 reference source code package - C implementations
3
4 Written in 2012 by Samuel Neves <[email protected]>
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
blake2b_set_lastnode(blake2b_state * S)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
blake2b_is_lastblock(const blake2b_state * S)46 blake2b_is_lastblock(const blake2b_state *S)
47 {
48 return S->f[0] != 0;
49 }
50
51 static inline int
blake2b_set_lastblock(blake2b_state * S)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
blake2b_increment_counter(blake2b_state * S,const uint64_t inc)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
blake2b_param_set_salt(blake2b_param * P,const uint8_t salt[BLAKE2B_SALTBYTES])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
blake2b_param_set_personal(blake2b_param * P,const uint8_t personal[BLAKE2B_PERSONALBYTES])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
blake2b_init0(blake2b_state * S)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
blake2b_init_param(blake2b_state * S,const blake2b_param * P)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
blake2b_init(blake2b_state * S,const uint8_t outlen)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
blake2b_init_salt_personal(blake2b_state * S,const uint8_t outlen,const void * salt,const void * personal)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
blake2b_init_key(blake2b_state * S,const uint8_t outlen,const void * key,const uint8_t keylen)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
blake2b_init_key_salt_personal(blake2b_state * S,const uint8_t outlen,const void * key,const uint8_t keylen,const void * salt,const void * personal)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
blake2b_update(blake2b_state * S,const uint8_t * in,uint64_t inlen)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
blake2b_final(blake2b_state * S,uint8_t * out,uint8_t outlen)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
blake2b(uint8_t * out,const void * in,const void * key,const uint8_t outlen,const uint64_t inlen,uint8_t keylen)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
blake2b_salt_personal(uint8_t * out,const void * in,const void * key,const uint8_t outlen,const uint64_t inlen,uint8_t keylen,const void * salt,const void * personal)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
blake2b_pick_best_implementation(void)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