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
28static blake2b_compress_fn blake2b_compress = blake2b_compress_ref;
29
30static const uint64_t blake2b_IV[8] = {
31    0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL,
32    0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
33    0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
34};
35
36/* LCOV_EXCL_START */
37static inline int
38blake2b_set_lastnode(blake2b_state *S)
39{
40    S->f[1] = -1;
41    return 0;
42}
43/* LCOV_EXCL_STOP */
44
45static inline int
46blake2b_is_lastblock(const blake2b_state *S)
47{
48    return S->f[0] != 0;
49}
50
51static inline int
52blake2b_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
61static inline int
62blake2b_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 */
77static inline int
78blake2b_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
84static inline int
85blake2b_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
92static inline int
93blake2b_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 */
106int
107blake2b_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
123int
124blake2b_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
145int
146blake2b_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
176int
177blake2b_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
213int
214blake2b_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 */
260int
261blake2b_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
289int
290blake2b_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. */
332int
333blake2b(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
369int
370blake2b_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
408int
409blake2b_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