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