Home | History | Annotate | Line # | Download | only in ref
      1 /*
      2    BLAKE2 reference source code package - C implementations
      3 
      4    Written in 2012 by Samuel Neves <sneves (at) 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     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     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