xref: /freebsd/sys/contrib/libsodium/src/libsodium/crypto_pwhash/argon2/blake2b-long.c (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
1 #include <limits.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "crypto_generichash_blake2b.h"
7 #include "private/common.h"
8 #include "utils.h"
9 
10 #include "blake2b-long.h"
11 
12 int
blake2b_long(void * pout,size_t outlen,const void * in,size_t inlen)13 blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen)
14 {
15     uint8_t *out = (uint8_t *) pout;
16     crypto_generichash_blake2b_state blake_state;
17     uint8_t outlen_bytes[4 /* sizeof(uint32_t) */] = { 0 };
18     int     ret = -1;
19 
20     if (outlen > UINT32_MAX) {
21         goto fail; /* LCOV_EXCL_LINE */
22     }
23 
24     /* Ensure little-endian byte order! */
25     STORE32_LE(outlen_bytes, (uint32_t) outlen);
26 
27 #define TRY(statement)   \
28     do {                 \
29         ret = statement; \
30         if (ret < 0) {   \
31             goto fail;   \
32         }                \
33     } while ((void) 0, 0)
34 
35     if (outlen <= crypto_generichash_blake2b_BYTES_MAX) {
36         TRY(crypto_generichash_blake2b_init(&blake_state, NULL, 0U, outlen));
37         TRY(crypto_generichash_blake2b_update(&blake_state, outlen_bytes,
38                                               sizeof(outlen_bytes)));
39         TRY(crypto_generichash_blake2b_update(
40             &blake_state, (const unsigned char *) in, inlen));
41         TRY(crypto_generichash_blake2b_final(&blake_state, out, outlen));
42     } else {
43         uint32_t toproduce;
44         uint8_t  out_buffer[crypto_generichash_blake2b_BYTES_MAX];
45         uint8_t  in_buffer[crypto_generichash_blake2b_BYTES_MAX];
46         TRY(crypto_generichash_blake2b_init(
47             &blake_state, NULL, 0U, crypto_generichash_blake2b_BYTES_MAX));
48         TRY(crypto_generichash_blake2b_update(&blake_state, outlen_bytes,
49                                               sizeof(outlen_bytes)));
50         TRY(crypto_generichash_blake2b_update(
51             &blake_state, (const unsigned char *) in, inlen));
52         TRY(crypto_generichash_blake2b_final(
53             &blake_state, out_buffer, crypto_generichash_blake2b_BYTES_MAX));
54         memcpy(out, out_buffer, crypto_generichash_blake2b_BYTES_MAX / 2);
55         out += crypto_generichash_blake2b_BYTES_MAX / 2;
56         toproduce =
57             (uint32_t) outlen - crypto_generichash_blake2b_BYTES_MAX / 2;
58 
59         while (toproduce > crypto_generichash_blake2b_BYTES_MAX) {
60             memcpy(in_buffer, out_buffer, crypto_generichash_blake2b_BYTES_MAX);
61             TRY(crypto_generichash_blake2b(
62                 out_buffer, crypto_generichash_blake2b_BYTES_MAX, in_buffer,
63                 crypto_generichash_blake2b_BYTES_MAX, NULL, 0U));
64             memcpy(out, out_buffer, crypto_generichash_blake2b_BYTES_MAX / 2);
65             out += crypto_generichash_blake2b_BYTES_MAX / 2;
66             toproduce -= crypto_generichash_blake2b_BYTES_MAX / 2;
67         }
68 
69         memcpy(in_buffer, out_buffer, crypto_generichash_blake2b_BYTES_MAX);
70         TRY(crypto_generichash_blake2b(out_buffer, toproduce, in_buffer,
71                                        crypto_generichash_blake2b_BYTES_MAX,
72                                        NULL, 0U));
73         memcpy(out, out_buffer, toproduce);
74     }
75 fail:
76     sodium_memzero(&blake_state, sizeof(blake_state));
77     return ret;
78 #undef TRY
79 }
80