summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/kit/CMakeLists.txt8
-rw-r--r--source/kit/mersenne_twister_64.c27
-rw-r--r--source/kit/secure_random.c91
-rw-r--r--source/kit/secure_random.h22
-rw-r--r--source/test/unittests/CMakeLists.txt4
-rw-r--r--source/test/unittests/secure_random.test.c22
6 files changed, 150 insertions, 24 deletions
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
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/mutex.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/status.h>
@@ -18,6 +19,7 @@ target_sources(
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/condition_variable.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/async_function.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/move_back.h>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/secure_random.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/input_stream.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/input_buffer.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/lower_bound.h>
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 <stdio.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <Windows.h>
+#else
+# include <unistd.h>
+#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 <stddef.h>
+#include <stdint.h>
+
+#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 <string.h>
+
+#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);
+}