From 11d4bbf1da658b85752173cccd9e92997c985681 Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 10 Aug 2025 05:24:25 +0300 Subject: [PATCH] crypto: generate_system_random_bytes_* refactored: improved error handling, win32 version moved to BCrypt API, split into normal and _or_die funcs Thanks to @gitToki for spotting the error handling issue! --- src/CMakeLists.txt | 8 +++- src/crypto/random.c | 94 ++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27739818..e6bdcea2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,13 +115,17 @@ else() set_source_files_properties("crypto/chacha8_stream.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-strict-prototypes") endif() +if(WIN32) + set(BCRYPT_LIB bcrypt) +endif() + add_library(crypto ${CRYPTO}) if(USE_BITCOIN_SECP256K1_FOR_ECDSA) add_dependencies(crypto secp256k1) - target_link_libraries(crypto secp256k1) + target_link_libraries(crypto secp256k1 ${BCRYPT_LIB}) else() add_dependencies(crypto OpenSSL::Crypto) - target_link_libraries(crypto OpenSSL::Crypto) + target_link_libraries(crypto OpenSSL::Crypto ${BCRYPT_LIB}) endif() add_library(currency_core ${CURRENCY_CORE}) diff --git a/src/crypto/random.c b/src/crypto/random.c index e38fb18d..f204c163 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "hash-ops.h" #include "random.h" @@ -15,19 +17,29 @@ static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE"); #if defined(_WIN32) #include -#include +#include -void generate_system_random_bytes_no_lock(size_t n, void *result) { - HCRYPTPROV prov; -#define must_succeed(x) do if (!(x)) assert(0); while (0) - if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) +// thread-safe version +bool generate_system_random_bytes(size_t n, void *result) +{ + if (n == 0) + return true; + + if (result == NULL) + return false; + + NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)result, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG); + return BCRYPT_SUCCESS(status); +} + +void generate_system_random_bytes_or_die(size_t n, void *result) +{ + if (!generate_system_random_bytes(n, result)) { - int err = GetLastError(); - assert(0); + fprintf(stderr, "Error: generate_system_random_bytes failed and this is fatal\n\n"); + fflush(stderr); + _exit(EXIT_FAILURE); } - must_succeed(CryptGenRandom(prov, (DWORD)n, result)); - must_succeed(CryptReleaseContext(prov, 0)); -#undef must_succeed } #else @@ -40,28 +52,49 @@ void generate_system_random_bytes_no_lock(size_t n, void *result) { #include #include -void generate_system_random_bytes_no_lock(size_t n, void *result) { +bool generate_system_random_bytes(size_t n, void *result) +{ int fd; - if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) { - exit(EXIT_FAILURE); - } - for (;;) { - ssize_t res = read(fd, result, n); - if ((size_t) res == n) { - break; - } - if (res < 0) { - if (errno != EINTR) { - exit(EXIT_FAILURE); + + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd < 0) + return false; + + size_t bytes_read = 0; + while (bytes_read < n) + { + ssize_t res = read(fd, (char*)result + bytes_read, n - bytes_read); + if (res < 0) + { + if (errno != EINTR) + { + close(fd); + return false; } - } else if (res == 0) { - exit(EXIT_FAILURE); - } else { - result = padd(result, (size_t) res); - n -= (size_t) res; + // EINTR - interrupted by signal, continue reading + } + else if (res == 0) + { + // EOF - should not happen with /dev/urandom + close(fd); + return false; + } + else + { + bytes_read += res; } } - if (close(fd) < 0) { + + close(fd); // don't check, 'cuz failing to close /dev/urandom is not truly fatal, the OS will clean up + return true; +} + +void generate_system_random_bytes_or_die(size_t n, void *result) +{ + if (!generate_system_random_bytes(n, result)) + { + fprintf(stderr, "FATAL: Failed to generate %zu random bytes: %s\n\n", n, strerror(errno)); + fflush(stderr); exit(EXIT_FAILURE); } } @@ -85,11 +118,10 @@ FINALIZER(deinit_random) { } */ -//INITIALIZER(init_random) { void init_random(void) { - generate_system_random_bytes_no_lock(RANDOM_STATE_SIZE, &state); - //REGISTER_FINA\LIZER(deinit_random); + generate_system_random_bytes_or_die(HASH_DATA_AREA, &state); + #if !defined(NDEBUG) assert(curstate == 0); curstate = 1;