diff options
Diffstat (limited to 'libhashsum_init_blake2b_hasher.c')
-rw-r--r-- | libhashsum_init_blake2b_hasher.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/libhashsum_init_blake2b_hasher.c b/libhashsum_init_blake2b_hasher.c new file mode 100644 index 0000000..57be6fe --- /dev/null +++ b/libhashsum_init_blake2b_hasher.c @@ -0,0 +1,202 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifdef SUPPORT_BLAKE2B + + +#define BLAKE2B_BLOCK_SIZE 128U + + +LIBHASHSUM_1_NONNULL_ +static size_t +process(struct libhashsum_hasher *this, const void *data, size_t bytes) +{ + if (this->state.blake2b.keybytes && bytes) { + libblake_blake2b_force_update(&this->state.blake2b.s, this->state.blake2b.buf, BLAKE2B_BLOCK_SIZE); + this->state.blake2b.keybytes = 0; + memset(this->state.blake2b.buf, 0, (size_t)this->state.blake2b.keybytes); + } + return libblake_blake2b_update(&this->state.blake2b.s, data, bytes); +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise_const(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits) +{ + const unsigned char *m = data; + size_t r; + + if (extra_bits) { + errno = EINVAL; + return -1; + } + + r = process(this, data, bytes); + m = &m[r]; + bytes -= r; + + if (!this->hash_output) + this->hash_output = this->state.blake2b.buf; + + if (this->state.blake2b.keybytes) + bytes = BLAKE2B_BLOCK_SIZE; + else + memcpy(this->state.blake2b.buf, m, bytes); + libblake_blake2b_digest(&this->state.blake2b.s, this->state.blake2b.buf, + bytes, 0, this->hash_size, this->hash_output); + + memset(&this->state.blake2b.s, 0, sizeof(this->state.blake2b.s)); + this->state.blake2b.keybytes = 0; + return 0; +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size) +{ + unsigned char *m = data; + size_t r; + + if (extra_bits) { + errno = EINVAL; + return -1; + } + + r = process(this, data, bytes); + m = &m[r]; + bytes -= r; + size -= r; + + if (!this->hash_output) + this->hash_output = this->state.blake224.buf; + + if (this->state.blake2b.keybytes) { + bytes = BLAKE2B_BLOCK_SIZE; + m = this->state.blake2b.buf; + } else if (size < libblake_blake2b_digest_get_required_input_size(bytes)) { + memcpy(this->state.blake2b.buf, m, bytes); + m = this->state.blake2b.buf; + } + libblake_blake2b_digest(&this->state.blake2b.s, m, bytes, 0, this->hash_size, this->hash_output); + + memset(&this->state.blake2b.s, 0, sizeof(this->state.blake2b.s)); + this->state.blake2b.keybytes = 0; + return 0; +} + + +#if defined(__GNUC__) +__attribute__((__pure__)) +#endif +static int +allzeroes(const uint8_t *data, size_t n) +{ + if (data) + while (n--) + if (data[n]) + return 0; + return 1; +} + + +static char * +hex(char *buf, const uint8_t *data, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) { + *buf++ = "0123456789abcdef"[(data[i] >> 4) & 15]; + *buf++ = "0123456789abcdef"[(data[i] >> 0) & 15]; + } + return buf; +} + + +static const char * +mkalgostr(char *buf, const char *name, size_t hashbits, const uint8_t *salt, + const uint8_t *pepper, size_t salt_pepper_bytes, const uint8_t *key, size_t keybytes) +{ + char *p, *b; + int with_salt = (salt && !allzeroes(salt, salt_pepper_bytes)); + int with_pepper = (pepper && !allzeroes(pepper, salt_pepper_bytes)); + if (!hashbits && !with_salt && !with_pepper && !keybytes) + return name; + b = p = stpcpy(buf, name); + if (hashbits) + p = &p[sprintf(p, ",n=%zu", hashbits)]; + if (with_salt) + p = hex(stpcpy(p, ",salt="), salt, salt_pepper_bytes); + if (with_pepper) + p = hex(stpcpy(p, ",pepper="), pepper, salt_pepper_bytes); + if (keybytes) + p = hex(stpcpy(p, ",key="), key, keybytes); + *b = '['; + *p++ = ']'; + *p++ = '\0'; + return buf; +} + + +int +libhashsum_init_blake2b_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, + const void *pepper, const void *key, size_t keybits) +{ + struct libblake_blake2b_params params = { + .digest_len = (unsigned char)(hashbits / 8U), + .key_len = (unsigned char)(keybits / 8U), + .fanout = 1U, + .depth = 1U, + .leaf_len = 0U, + .node_offset = 0U, + .node_depth = 0U, + .inner_len = 0U + }; + if (((hashbits | keybits) & 7U) || ((hashbits | keybits) > 256U)) { + errno = EINVAL; + return -1; + } + if (!hashbits) + hashbits = 512U; + libblake_init(); + this->algorithm = LIBHASHSUM_BLAKE2B; + this->algorithm_string = mkalgostr(this->state.blake2b.algostr, "BLAKE2b", + hashbits == 512U ? 0U : hashbits, + salt, pepper, 16U, key, keybits / 8U); + this->input_block_size = BLAKE2B_BLOCK_SIZE; + this->hash_size = hashbits / 8U; + this->hash_output = NULL; + this->supports_non_whole_bytes = 0; + this->process = &process; + this->finalise_const = &finalise_const; + this->finalise = &finalise; + this->stretch = NULL; + this->destroy = NULL; + if (salt) + memcpy(params.salt, salt, sizeof(params.salt)); + if (pepper) + memcpy(params.pepper, pepper, sizeof(params.pepper)); + this->state.blake2b.keybytes = (unsigned char)(keybits / 8U); + if (this->state.blake2b.keybytes) { + memcpy(this->state.blake2b.buf, key, keybits / 8U); + memset(&this->state.blake2b.buf[keybits / 8U], 0, sizeof(this->state.blake2b.buf) - keybits / 8U); + } + libblake_blake2b_init(&this->state.blake2b.s, ¶ms); + return 0; +} + + +#else +int +libhashsum_init_blake2b_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt, + const void *pepper, const void *key, size_t keybits) +{ + (void) this; + (void) hashbits; + (void) salt; + (void) pepper; + (void) key; + (void) keybits; + errno = ENOSYS; + return -1; +} +#endif |