From 0cbfbd63d86b63cef88f349119d1a4b551c0a862 Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Sun, 2 Jun 2024 09:52:32 -0300 Subject: src/hash.c: Add thread safe initialization of SipHash seed --- Makefile | 2 +- deps.mk | 9 ++++++ src/hash.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hash.h | 8 +++++ tests/hash.c | 63 ++++++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/hash.c create mode 100644 src/hash.h create mode 100644 tests/hash.c diff --git a/Makefile b/Makefile index ffc06f4..088d839 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ MANDIR = $(SHAREDIR)/man EXEC = ./ ## Where to store the installation. Empty by default. DESTDIR = -LDLIBS = -lsiphashbs +LDLIBS = -lpthread -lsiphashbs diff --git a/deps.mk b/deps.mk index ee1bcb4..12678b6 100644 --- a/deps.mk +++ b/deps.mk @@ -4,6 +4,7 @@ catalogs.msg = $(catalogs.en.msg) sources.c = \ src/catalog.c \ + src/hash.c \ src/i18n.c \ src/lib.c \ src/logerr.c \ @@ -18,6 +19,7 @@ sources.c = \ tests.c = \ tests/catalog.c \ + tests/hash.c \ tests/i18n.c \ tests/lib.c \ tests/logerr.c \ @@ -31,6 +33,7 @@ tests.c = \ tests/vector.c \ src/catalog.o: src/catalog.h +src/hash.o: src/hash.h src/i18n.o: src/i18n.h src/lib.o: src/lib.h src/logerr.o: src/logerr.h @@ -44,6 +47,7 @@ src/util.o: src/util.h src/vector.o: src/vector.h tests/catalog.o: src/catalog.c src/catalog.h +tests/hash.o: src/hash.c src/hash.h tests/i18n.o: src/i18n.c src/i18n.h tests/lib.o: src/lib.c src/lib.h tests/logerr.o: src/logerr.c src/logerr.h @@ -57,6 +61,7 @@ tests/util.o: src/util.c src/util.h tests/vector.o: src/vector.c src/vector.h tests/catalog.a: tests/catalog.o +tests/hash.a: tests/hash.o tests/i18n.a: tests/i18n.o tests/lib.a: tests/lib.o tests/logerr.a: tests/logerr.o @@ -70,6 +75,7 @@ tests/util.a: tests/util.o tests/vector.a: tests/vector.o tests/catalog.bin-check: tests/catalog.bin +tests/hash.bin-check: tests/hash.bin tests/i18n.bin-check: tests/i18n.bin tests/lib.bin-check: tests/lib.bin tests/logerr.bin-check: tests/logerr.bin @@ -84,6 +90,7 @@ tests/vector.bin-check: tests/vector.bin src/catalog.o: src/logerr.h +src/hash.o: src/logerr.h src/random.h src/i18n.o: src/catalog.h src/lib.o: src/logerr.h src/logerr.o: @@ -97,6 +104,7 @@ src/util.o: src/logerr.h src/vector.o: src/catalog.h src/i18n.h src/logerr.h src/math.h src/util.h tests/catalog.o: src/logerr.h src/testing.h src/util.h tests/slurp.h +tests/hash.o: src/logerr.h src/random.h src/testing.h tests/i18n.o: src/catalog.h src/logerr.h tests/lib.o: src/logerr.h tests/logerr.o: src/testing.h src/util.h tests/slurp.h @@ -110,6 +118,7 @@ tests/util.o: src/logerr.h src/testing.h tests/slurp.h tests/vector.o: src/catalog.h src/i18n.h src/logerr.h src/math.h src/util.h src/testing.h tests/catalog.a: src/logerr.o src/testing.o src/util.o tests/slurp.o +tests/hash.a: src/logerr.o src/random.o src/testing.o src/util.o tests/i18n.a: src/catalog.o src/logerr.o tests/lib.a: src/logerr.o tests/logerr.a: src/testing.o src/util.o tests/slurp.o diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..4b397bd --- /dev/null +++ b/src/hash.c @@ -0,0 +1,104 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hash.h" +#include "logerr.h" +#include "random.h" + + + +static volatile bool +INITIALIZED = false; + +static uint8_t +SIPHASH_KEY[SIPHASH_KEY_LENGTH]; + +static pthread_mutex_t +SEED_MUTEX = PTHREAD_MUTEX_INITIALIZER; + + + +static int +unsafe_init(void) { + int rc = -1; + + if (urandom_bytes(SIPHASH_KEY_LENGTH, &SIPHASH_KEY)) { + logerr("urandom_bytes()"); + goto out; + } + + rc = 0; +out: + return rc; +} + +static int +safe_init(void) { + int rc = -1; + + bool lock_acquired = false; + + if (INITIALIZED == true) { + rc = 0; + goto out; + } + + const int ret1 = pthread_mutex_lock(&SEED_MUTEX); + if (ret1) { + logerr("pthread_mutex_lock(): %s", strerror(ret1)); + goto out; + } + lock_acquired = true; + + if (INITIALIZED == true) { + rc = 0; + goto out; + } + + if (unsafe_init()) { + logerr("unsafe_init()"); + goto out; + } + + INITIALIZED = true; + + rc = 0; +out: + if (lock_acquired) { + const int ret2 = pthread_mutex_unlock(&SEED_MUTEX); + if (ret2) { + logerr("pthread_mutex_unlock(): %s", strerror(ret2)); + rc = -1; + } + } + return rc; +} + +static void +ensure_initialized(void) { + assert((safe_init() == 0) && "Failed to initialized the hash seed"); +} + +int +hash_init(void) { + return safe_init(); +} + +void +hash( + const size_t inlen, + const void *const restrict in, + uint8_t out[HASH_OUTPUT_LENGTH] +) { + ensure_initialized(); + siphashbs(SIPHASH_KEY, inlen, in, out); +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..4831c4b --- /dev/null +++ b/src/hash.h @@ -0,0 +1,8 @@ +#define HASH_OUTPUT_LENGTH 16U + +void +hash( + const size_t inlen, + const void *const restrict in, + uint8_t out[HASH_OUTPUT_LENGTH] +); diff --git a/tests/hash.c b/tests/hash.c new file mode 100644 index 0000000..652b4fd --- /dev/null +++ b/tests/hash.c @@ -0,0 +1,63 @@ +#include "../src/hash.c" + +#include + +#include "../src/testing.h" + + + +static void +test_HASH_OUTPUT_LENGTH(void) { + test_start("HASH_OUTPUT_LENGTH"); + + { + testing("Enforce we're always consistent with SipHash"); + + assert(HASH_OUTPUT_LENGTH == SIPHASH_OUTPUT_LENGTH); + + test_ok(); + } +} + +static int +test_hash_init(void) { + int rc = -1; + + test_start("hash_init()"); + + { + testing("INITIALIZED changes after calling hash_init()"); + + assert(INITIALIZED == false); + + if (hash_init()) { + logerr("hash_init()"); + goto out; + } + rc = 0; goto out; + + assert(INITIALIZED == true); + + test_ok(); + } + + rc = 0; +out: + return rc; +} + +int +main(void) { + int rc = EXIT_FAILURE; + + test_HASH_OUTPUT_LENGTH(); + + if (test_hash_init()) { + logerr("test_hash_init()"); + goto out; + } + + rc = EXIT_SUCCESS; +out: + return rc; +} -- cgit v1.2.3