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