crypto: random and siphash static-init-safety

Co-authored-by: Thomas <thomas.giudici@proton.me>
Co-authored-by: selsta <selsta@sent.at>
This commit is contained in:
jeffro256
2026-09-22 16:01:01 -05:00
co-authored by Thomas selsta
parent f978eab613
commit 92582340a2
5 changed files with 62 additions and 10 deletions
+13 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2019-2024, The Monero Project
// Copyright (c) 2019-2026, The Monero Project
//
// All rights reserved.
//
@@ -48,6 +48,12 @@
#define CTHR_THREAD_JOIN(thr) do { WaitForSingleObject(thr, INFINITE); CloseHandle(thr); } while(0)
#define CTHR_THREAD_CLOSE(thr) CloseHandle((HANDLE)thr);
#define CTHR_ONCE_FLAG INIT_ONCE
#define CTHR_ONCE_INIT INIT_ONCE_STATIC_INIT
#define CTHR_ONCE_CALL(flag, f) (0 != InitOnceExecuteOnce(flag, f, NULL, NULL))
#define CTHR_ONCE_DECLARE_CB(name) BOOL CALLBACK name(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
#define CTHR_ONCE_CB_SUCCESS true
#else
#include <pthread.h>
@@ -67,4 +73,10 @@
#define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL)
#define CTHR_THREAD_CLOSE(thr) pthread_detach(thr)
#define CTHR_ONCE_FLAG pthread_once_t
#define CTHR_ONCE_INIT PTHREAD_ONCE_INIT
#define CTHR_ONCE_CALL(flag, f) (0 == pthread_once(flag, f))
#define CTHR_ONCE_DECLARE_CB(name) void name(void)
#define CTHR_ONCE_CB_SUCCESS
#endif
+3 -2
View File
@@ -73,12 +73,13 @@ namespace crypto { \
namespace crypto {
inline std::size_t siphash_to_size_t(const void *data, std::size_t length) {
static_assert(sizeof(crypto_siphash_key) == crypto_shorthash_siphash24_KEYBYTES,
static_assert(16 == crypto_shorthash_siphash24_KEYBYTES,
"crypto_siphash_key size must match the SipHash-2-4 key length");
static_assert(sizeof(std::uint64_t) == crypto_shorthash_siphash24_BYTES,
"std::uint64_t size must match the SipHash-2-4 digest length");
std::uint64_t h;
crypto_shorthash_siphash24(reinterpret_cast<unsigned char*>(&h), static_cast<const unsigned char*>(data), length, crypto_siphash_key);
crypto_shorthash_siphash24(reinterpret_cast<unsigned char*>(&h), static_cast<const unsigned char*>(data), length,
get_static_siphash_key());
return h;
}
}
+42 -5
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2024, The Monero Project
// Copyright (c) 2014-2026, The Monero Project
//
// All rights reserved.
//
@@ -32,6 +32,7 @@
#include <stddef.h>
#include <string.h>
#include "c_threads.h"
#include "hash-ops.h"
#include "initializer.h"
#include "random.h"
@@ -97,18 +98,22 @@ static void generate_system_random_bytes(size_t n, void *result) {
#endif
static union hash_state state;
unsigned char crypto_siphash_key[16];
static unsigned char crypto_siphash_key[16];
#if !defined(NDEBUG)
static volatile int curstate; /* To catch thread safety problems. */
#endif
static CTHR_ONCE_FLAG init_random_once = CTHR_ONCE_INIT;
FINALIZER(deinit_random) {
#if !defined(NDEBUG)
assert(curstate == 1);
assert(curstate == 1 || curstate == 0);
curstate = 0;
#endif
memset(&state, 0, sizeof(union hash_state));
}
FINALIZER(deinit_sip) {
memset(crypto_siphash_key, 0, sizeof(crypto_siphash_key));
}
@@ -122,19 +127,20 @@ static void lock_random_state(void) {
#define HASH_CAPACITY_AREA 64
INITIALIZER(init_random) {
static CTHR_ONCE_DECLARE_CB(init_random) {
static_assert(sizeof(state) == HASH_DATA_AREA + HASH_CAPACITY_AREA,
"Keccak state is the wrong size");
lock_random_state();
generate_system_random_bytes(HASH_DATA_AREA, &state);
hash_permutation(&state);
generate_system_random_bytes(sizeof(crypto_siphash_key), crypto_siphash_key);
REGISTER_FINALIZER(deinit_random);
#if !defined(NDEBUG)
assert(curstate == 0);
curstate = 1;
#endif
return CTHR_ONCE_CB_SUCCESS;
}
void generate_random_bytes_not_thread_safe(size_t n, void *result) {
@@ -144,6 +150,9 @@ void generate_random_bytes_not_thread_safe(size_t n, void *result) {
* leaving this function does not leak the previous squeezed values.
*/
const int r = CTHR_ONCE_CALL(&init_random_once, init_random);
(void) r; assert(r);
#if !defined(NDEBUG)
assert(curstate == 1);
curstate = 2;
@@ -171,6 +180,14 @@ void generate_random_bytes_not_thread_safe(size_t n, void *result) {
void add_extra_entropy_not_thread_safe(const void *ptr, size_t bytes)
{
const int r = CTHR_ONCE_CALL(&init_random_once, init_random);
(void) r; assert(r);
#if !defined(NDEBUG)
assert(curstate == 1);
curstate = 2;
#endif
size_t i;
while (bytes > 0)
@@ -182,4 +199,24 @@ void add_extra_entropy_not_thread_safe(const void *ptr, size_t bytes)
ptr = cpadd(ptr, round_bytes);
hash_permutation(&state);
}
#if !defined(NDEBUG)
assert(curstate == 2);
curstate = 1;
#endif
}
static CTHR_ONCE_DECLARE_CB(init_sip)
{
generate_system_random_bytes(sizeof(crypto_siphash_key), crypto_siphash_key);
REGISTER_FINALIZER(deinit_sip);
return CTHR_ONCE_CB_SUCCESS;
}
const unsigned char *get_static_siphash_key(void)
{
static CTHR_ONCE_FLAG once = CTHR_ONCE_INIT;
const int r = CTHR_ONCE_CALL(&once, init_sip);
(void) r; assert(r);
return crypto_siphash_key;
}
+3 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2024, The Monero Project
// Copyright (c) 2014-2026, The Monero Project
//
// All rights reserved.
//
@@ -39,7 +39,8 @@ extern "C" {
void generate_random_bytes_not_thread_safe(size_t n, void *result);
void add_extra_entropy_not_thread_safe(const void *ptr, size_t bytes);
extern unsigned char crypto_siphash_key[16];
//! @brief Return pointer to random, constant 16-byte key, thread-safe and static-init-safe
const unsigned char *get_static_siphash_key(void);
#ifdef __cplusplus
}
+1
View File
@@ -33,6 +33,7 @@
#include "crypto-tests.h"
void setup_random(void) {
generate_random_bytes_not_thread_safe(0, NULL);
memset(&state, 42, sizeof(union hash_state));
hash_permutation(&state);
}