From 243d191aafdec9e11edea857f93b8ca6c6c7d318 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sat, 17 Dec 2022 22:50:24 +0100 Subject: secure random --- source/kit/CMakeLists.txt | 8 ++- source/kit/mersenne_twister_64.c | 27 +++------ source/kit/secure_random.c | 91 ++++++++++++++++++++++++++++++ source/kit/secure_random.h | 22 ++++++++ source/test/unittests/CMakeLists.txt | 4 +- source/test/unittests/secure_random.test.c | 22 ++++++++ 6 files changed, 150 insertions(+), 24 deletions(-) create mode 100644 source/kit/secure_random.c create mode 100644 source/kit/secure_random.h create mode 100644 source/test/unittests/secure_random.test.c diff --git a/source/kit/CMakeLists.txt b/source/kit/CMakeLists.txt index 5954992..f9a30d2 100644 --- a/source/kit/CMakeLists.txt +++ b/source/kit/CMakeLists.txt @@ -2,9 +2,10 @@ target_sources( ${KIT_LIBRARY} PRIVATE input_buffer.c bigint.c status.c threads.win32.c time.c - atomic.win32.c threads.posix.c condition_variable.c move_back.c - input_stream.c lower_bound.c file.c string_ref.c async_function.c - allocator.c array_ref.c dynamic_array.c mutex.c mersenne_twister_64.c + secure_random.c atomic.win32.c threads.posix.c condition_variable.c + move_back.c input_stream.c lower_bound.c file.c string_ref.c + async_function.c allocator.c array_ref.c dynamic_array.c mutex.c + mersenne_twister_64.c PUBLIC $ $ @@ -18,6 +19,7 @@ target_sources( $ $ $ + $ $ $ $ diff --git a/source/kit/mersenne_twister_64.c b/source/kit/mersenne_twister_64.c index 06f8535..28f8b3b 100644 --- a/source/kit/mersenne_twister_64.c +++ b/source/kit/mersenne_twister_64.c @@ -1,13 +1,11 @@ #include "mersenne_twister_64.h" -#include "time.h" +#include "secure_random.h" -enum { - MM = 156, - MATRIX_A = 0xb5026f5aa96619e9ull, - UM = 0xffffffff80000000ull, - LM = 0x7fffffffull -}; +#define MM 156 +#define MATRIX_A 0xb5026f5aa96619e9ull +#define UM 0xffffffff80000000ull +#define LM 0x7fffffffull void kit_mt64_init_array(kit_mt64_state_t *const state, ptrdiff_t const size, @@ -64,16 +62,7 @@ uint64_t kit_mt64_generate(kit_mt64_state_t *const state) { } uint64_t kit_mt64_seed() { - static uint64_t n = 0; - - struct timespec t; - timespec_get(&t, TIME_UTC); - - uint64_t seed[2] = { (n++) ^ (uint64_t) t.tv_sec, - (uint64_t) t.tv_nsec }; - - kit_mt64_state_t s; - kit_mt64_init_array(&s, sizeof seed / sizeof *seed, seed); - - return kit_mt64_generate(&s); + uint64_t seed; + kit_secure_random(sizeof seed, &seed); + return seed; } diff --git a/source/kit/secure_random.c b/source/kit/secure_random.c new file mode 100644 index 0000000..24e8173 --- /dev/null +++ b/source/kit/secure_random.c @@ -0,0 +1,91 @@ +#include "secure_random.h" + +#include "mersenne_twister_64.h" +#include "time.h" +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +# include +#else +# include +#endif + +static uint64_t get_available_memory() { +#if defined(_WIN32) && !defined(__CYGWIN__) + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + return (uint64_t) status.ullTotalPhys; +#else + uint64_t pages = (uint64_t) sysconf(_SC_PHYS_PAGES); + uint64_t page_size = (uint64_t) sysconf(_SC_PAGE_SIZE); + return pages * page_size; +#endif +} + +static void secure_random_fallback(ptrdiff_t const size, + void *const data) { + /* Try to get some unpredictable system properties and use them to + * seed the pseudo random number generator. + */ + + static uint64_t n = 0; + static uint64_t time_sec = 0; + static uint64_t time_nsec = 0; + + struct timespec t; + timespec_get(&t, TIME_UTC); + + kit_mt64_state_t state; + + if (time_sec == 0 && time_nsec == 0) { + uint64_t seed[4] = { n++, get_available_memory(), + (uint64_t) t.tv_sec, (uint64_t) t.tv_nsec }; + kit_mt64_init_array(&state, sizeof seed / sizeof *seed, seed); + } else { + uint64_t seed[6] = { n++, + get_available_memory(), + (uint64_t) t.tv_sec, + (uint64_t) t.tv_nsec, + (uint64_t) t.tv_sec - time_sec, + (uint64_t) t.tv_nsec - time_nsec }; + kit_mt64_init_array(&state, sizeof seed / sizeof *seed, seed); + } + + time_sec = (uint64_t) t.tv_sec; + time_nsec = (uint64_t) t.tv_nsec; + + /* Bootstrap the generator. + */ + for (ptrdiff_t i = 0; i < KIT_MT64_N; i++) + kit_mt64_generate(&state); + + for (ptrdiff_t i = 0; i < size; i++) + ((uint8_t *) data)[i] = (uint8_t) (kit_mt64_generate(&state) >> + 56); +} + +void kit_secure_random(ptrdiff_t const size, void *const data) { + if (size <= 0) + return; + +#if defined(_WIN32) && !defined(__CYGWIN__) + secure_random_fallback(size, data); +#else + FILE *f = fopen("/dev/urandom", "rb"); + + if (f == NULL) { + secure_random_fallback(size, data); + return; + } + + if (fread(data, 1, size, f) != size) { + secure_random_fallback(size, data); + fclose(f); + return; + } + + fclose(f); + return; +#endif +} diff --git a/source/kit/secure_random.h b/source/kit/secure_random.h new file mode 100644 index 0000000..758478d --- /dev/null +++ b/source/kit/secure_random.h @@ -0,0 +1,22 @@ +#ifndef KIT_SECURE_RANDOM_H +#define KIT_SECURE_RANDOM_H + +#include "status.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void kit_secure_random(ptrdiff_t size, void *data); + +#ifndef KIT_DISABLE_SHORT_NAMES +# define secure_random kit_secure_random +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/test/unittests/CMakeLists.txt b/source/test/unittests/CMakeLists.txt index 261b69e..b2ef480 100644 --- a/source/test/unittests/CMakeLists.txt +++ b/source/test/unittests/CMakeLists.txt @@ -4,5 +4,5 @@ target_sources( async_function.test.c bigint.test.c mutex.test.c test_duration.test.c main.test.c string_ref.test.c atomic.test.c thread.test.c array_ref.test.c input_stream.test.c lower_bound.test.c - condition_variable.test.c mersenne_twister_64.test.c input_buffer.test.c - move_back.test.c dynamic_array.test.c file.test.c) + secure_random.test.c condition_variable.test.c mersenne_twister_64.test.c + input_buffer.test.c move_back.test.c dynamic_array.test.c file.test.c) diff --git a/source/test/unittests/secure_random.test.c b/source/test/unittests/secure_random.test.c new file mode 100644 index 0000000..ec0a7b2 --- /dev/null +++ b/source/test/unittests/secure_random.test.c @@ -0,0 +1,22 @@ +#include "../../kit/secure_random.h" +#include + +#define KIT_TEST_FILE secure_random +#include "../../kit_test/test.h" + +TEST("secure random") { + int v[20]; + memset(v, 0, sizeof v); + + secure_random(40, v); + secure_random(40, v + 10); + + int repeats = 0; + + for (int i = 1; i < sizeof v / sizeof *v; i++) + for (int j = 0; j < i; j++) + if (v[i] == v[j]) + repeats++; + + REQUIRE(repeats == 0); +} -- cgit v1.2.3