aboutsummaryrefslogblamecommitdiffstats
path: root/libhashsum_init_blake2s_hasher.c
blob: 0957b224d157c51a80be7f9221a49d6c09159d25 (plain) (tree)








































































































































































































                                                                                                                   
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifdef SUPPORT_BLAKE2S


#define BLAKE2S_BLOCK_SIZE 64U


LIBHASHSUM_1_NONNULL_
static size_t
process(struct libhashsum_hasher *this, const void *data, size_t bytes)
{
	if (this->state.blake2s.keybytes && bytes) {
		libblake_blake2s_force_update(&this->state.blake2s.s, this->state.blake2s.buf, BLAKE2S_BLOCK_SIZE);
		this->state.blake2s.keybytes = 0;
		memset(this->state.blake2s.buf, 0, (size_t)this->state.blake2s.keybytes);
	}
	return libblake_blake2s_update(&this->state.blake2s.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.blake2s.buf;

	if (this->state.blake2s.keybytes)
		bytes = BLAKE2S_BLOCK_SIZE;
	else
		memcpy(this->state.blake2s.buf, m, bytes);
	libblake_blake2s_digest(&this->state.blake2s.s, this->state.blake2s.buf,
	                        bytes, 0, this->hash_size, this->hash_output);

	memset(&this->state.blake2s.s, 0, sizeof(this->state.blake2s.s));
	this->state.blake2s.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.blake2s.keybytes) {
		bytes = BLAKE2S_BLOCK_SIZE;
		m = this->state.blake2s.buf;
	} else if (size < libblake_blake2s_digest_get_required_input_size(bytes)) {
		memcpy(this->state.blake2s.buf, m, bytes);
		m = this->state.blake2s.buf;
	}
	libblake_blake2s_digest(&this->state.blake2s.s, m, bytes, 0, this->hash_size, this->hash_output);

	memset(&this->state.blake2s.s, 0, sizeof(this->state.blake2s.s));
	this->state.blake2s.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 *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_blake2s_hasher(struct libhashsum_hasher *this, size_t hashbits, const void *salt,
                               const void *pepper, const void *key, size_t keybits)
{
	struct libblake_blake2s_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 = 256U;
	libblake_init();
	this->algorithm = LIBHASHSUM_BLAKE2S;
	this->algorithm_string = mkalgostr(this->state.blake2s.algostr, "BLAKE2s",
	                                   hashbits == 256U ? 0U : hashbits,
	                                   salt, pepper, 8U, key, keybits / 8U);
	this->input_block_size = BLAKE2S_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.blake2s.keybytes = (unsigned char)(keybits / 8U);
	if (this->state.blake2s.keybytes) {
		memcpy(this->state.blake2s.buf, key, keybits / 8U);
		memset(&this->state.blake2s.buf[keybits / 8U], 0, sizeof(this->state.blake2s.buf) - keybits / 8U);
	}
	libblake_blake2s_init(&this->state.blake2s.s, &params);
	return 0;
}


#else
int
libhashsum_init_blake2s_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