/* 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.blake2b.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) { while (n--) if (data[n]) return 0; return 1; } static char * hex(char *restrict buf, const uint8_t *restrict 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 > 512U || keybits > 512U) { errno = EINVAL; return -1; } if (!hashbits) { hashbits = 512U; params.digest_len = (unsigned char)(hashbits / 8U); } 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->standard_partial_byte_input_encoding = LIBHASHSUM_UNSUPPORTED; this->standard_partial_byte_output_encoding = LIBHASHSUM_UNSUPPORTED; 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