diff --git a/src/crypto/random.c b/src/crypto/random.c index b16d39c9..bdac1e7a 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -10,14 +10,14 @@ //#include "initializer.h" #include "random.h" -static void generate_system_random_bytes(size_t n, void *result); +static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE"); #if defined(_WIN32) #include #include -static void generate_system_random_bytes(size_t n, void *result) { +void generate_system_random_bytes(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)) @@ -40,7 +40,7 @@ static void generate_system_random_bytes(size_t n, void *result) { #include #include -static void generate_system_random_bytes(size_t n, void *result) { +void generate_system_random_bytes(size_t n, void *result) { int fd; if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) { err(EXIT_FAILURE, "open /dev/urandom"); @@ -68,7 +68,7 @@ static void generate_system_random_bytes(size_t n, void *result) { #endif -/* static */ union hash_state state; // NOTE: 'static' is commented out here to be able to store/load global random generator state in tests (see also random_helper.h) +static union hash_state state; #if !defined(NDEBUG) static volatile int curstate; /* To catch thread safety problems. */ @@ -105,6 +105,57 @@ void grant_random_initialize(void) } } +void random_prng_initialize_with_seed(uint64_t seed) +{ + grant_random_initialize(); +#if !defined(NDEBUG) + assert(curstate == 1); + curstate = 3; +#endif + memset(&state, 0, sizeof state); + memcpy(&state, &seed, sizeof seed); + for(size_t i = 0, count = seed & 31; i < count; ++i) + hash_permutation(&state); +#if !defined(NDEBUG) + assert(curstate == 3); + curstate = 1; +#endif +} + +void random_prng_get_state(void *state_buffer, const size_t buffer_size) +{ + grant_random_initialize(); +#if !defined(NDEBUG) + assert(curstate == 1); + curstate = 4; +#endif + + assert(sizeof state == buffer_size); + memcpy(state_buffer, &state, buffer_size); + +#if !defined(NDEBUG) + assert(curstate == 4); + curstate = 1; +#endif +} + +void random_prng_set_state(const void *state_buffer, const size_t buffer_size) +{ + grant_random_initialize(); +#if !defined(NDEBUG) + assert(curstate == 1); + curstate = 5; +#endif + + assert(sizeof state == buffer_size); + memcpy(&state, state_buffer, buffer_size); + +#if !defined(NDEBUG) + assert(curstate == 5); + curstate = 1; +#endif +} + void generate_random_bytes(size_t n, void *result) { grant_random_initialize(); #if !defined(NDEBUG) diff --git a/src/crypto/random.h b/src/crypto/random.h index 587d730c..dbc79302 100644 --- a/src/crypto/random.h +++ b/src/crypto/random.h @@ -1,3 +1,5 @@ +// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2014-2018 The Boolberry developers // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -5,6 +7,31 @@ #pragma once #include +#include + +// use the cryptographically secure Pseudo-Random Number Generator provided by the operating system +void generate_system_random_bytes(size_t n, void *result); void generate_random_bytes(size_t n, void *result); -void grant_random_initialize(void); \ No newline at end of file + +// checks if PRNG is initialized and initializes it if necessary +void grant_random_initialize(void); + +#define RANDOM_STATE_SIZE 200 + +// explicitly define USE_INSECURE_RANDOM_RPNG_ROUTINES for using random_initialize_with_seed +#ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES +// reinitializes PRNG with the given seed +// !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH! +// Use with care and ONLY for tests or debug purposes! +void random_prng_initialize_with_seed(uint64_t seed); + +// gets internal RPNG state (state_buffer should be 200 bytes long) +void random_prng_get_state(void *state_buffer, const size_t buffer_size); + +// sets internal RPNG state (state_buffer should be 200 bytes long) +// !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH! +// Use with care and ONLY for tests or debug purposes! +void random_prng_set_state(const void *state_buffer, const size_t buffer_size); + +#endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES diff --git a/tests/core_tests/random_helper.cpp b/tests/core_tests/random_helper.cpp index 3d02be79..6f1f7396 100644 --- a/tests/core_tests/random_helper.cpp +++ b/tests/core_tests/random_helper.cpp @@ -6,6 +6,21 @@ #include "chaingen.h" #include "random_helper.h" +random_state_test_restorer::random_state_test_restorer() +{ + crypto::random_prng_get_state(&m_state, sizeof m_state); +} + +random_state_test_restorer::~random_state_test_restorer() +{ + crypto::random_prng_set_state(&m_state, sizeof m_state); +} + +void random_state_test_restorer::reset_random(uint64_t seed /* = 0 */) +{ + crypto::random_prng_initialize_with_seed(seed); +} + std::string get_random_text(size_t len) { static const char text_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "~!@#$%^&*()-=_+\\/?,.<>|{}[]`';:\" "; diff --git a/tests/core_tests/random_helper.h b/tests/core_tests/random_helper.h index f32ec764..c9826665 100644 --- a/tests/core_tests/random_helper.h +++ b/tests/core_tests/random_helper.h @@ -1,40 +1,28 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2019 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once -#define RANDOM_STATE_SIZE 200 -extern "C" volatile union hash_state state; // field defined in random.c -static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE"); - // DISCLAIMER: designed for tests puposes ONLY! // This class is not intended to be used neither in multi-threaded environment nor in production. +#ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES + // Remebers random state at ctor, restores it at dtor struct random_state_test_restorer { - random_state_test_restorer() - { - memcpy(m_state, const_cast(&::state), RANDOM_STATE_SIZE); - } - - ~random_state_test_restorer() - { - memcpy(const_cast(&::state), m_state, RANDOM_STATE_SIZE); - } - - static void reset_random(uint64_t seed = 0) - { - memset(const_cast(&::state), 0, RANDOM_STATE_SIZE); - memcpy(const_cast(&::state), &seed, sizeof seed); - } + random_state_test_restorer(); + ~random_state_test_restorer(); + static void reset_random(uint64_t seed = 0); private: uint8_t m_state[RANDOM_STATE_SIZE]; }; +#endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES + std::string get_random_text(size_t len); bool random_state_manupulation_test();