Changeset View
Changeset View
Standalone View
Standalone View
src/random.cpp
Show All 9 Lines | |||||
#include <wincrypt.h> | #include <wincrypt.h> | ||||
#endif | #endif | ||||
#include <crypto/sha512.h> | #include <crypto/sha512.h> | ||||
#include <logging.h> // for LogPrint() | #include <logging.h> // for LogPrint() | ||||
#include <support/cleanse.h> | #include <support/cleanse.h> | ||||
#include <sync.h> // for WAIT_LOCK | #include <sync.h> // for WAIT_LOCK | ||||
#include <util/time.h> // for GetTime() | #include <util/time.h> // for GetTime() | ||||
#include <openssl/conf.h> | |||||
#include <openssl/err.h> | #include <openssl/err.h> | ||||
#include <openssl/rand.h> | #include <openssl/rand.h> | ||||
#include <chrono> | #include <chrono> | ||||
#include <cstdlib> | #include <cstdlib> | ||||
#include <limits> | #include <limits> | ||||
#include <mutex> | #include <mutex> | ||||
#include <thread> | #include <thread> | ||||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void GetRandBytes(uint8_t *buf, int num) { | void GetRandBytes(uint8_t *buf, int num) { | ||||
if (RAND_bytes(buf, num) != 1) { | if (RAND_bytes(buf, num) != 1) { | ||||
RandFailure(); | RandFailure(); | ||||
} | } | ||||
} | } | ||||
void LockingCallbackOpenSSL(int mode, int i, const char *file, int line); | |||||
namespace { | namespace { | ||||
struct RNGState { | struct RNGState { | ||||
Mutex m_mutex; | Mutex m_mutex; | ||||
uint8_t m_state[32] GUARDED_BY(m_mutex) = {0}; | uint8_t m_state[32] GUARDED_BY(m_mutex) = {0}; | ||||
uint64_t m_counter GUARDED_BY(m_mutex) = 0; | uint64_t m_counter GUARDED_BY(m_mutex) = 0; | ||||
std::unique_ptr<Mutex[]> m_mutex_openssl; | |||||
RNGState() { | |||||
InitHardwareRand(); | |||||
RNGState() { InitHardwareRand(); } | // Init OpenSSL library multithreading support | ||||
m_mutex_openssl.reset(new Mutex[CRYPTO_num_locks()]); | |||||
CRYPTO_set_locking_callback(LockingCallbackOpenSSL); | |||||
// OpenSSL can optionally load a config file which lists optional | |||||
// loadable modules and engines. We don't use them so we don't require | |||||
// the config. However some of our libs may call functions which attempt | |||||
// to load the config file, possibly resulting in an exit() or crash if | |||||
// it is missing or corrupt. Explicitly tell OpenSSL not to try to load | |||||
// the file. The result for our libs will be that the config appears to | |||||
// have been loaded and there are no modules/engines available. | |||||
OPENSSL_no_config(); | |||||
#ifdef WIN32 | |||||
// Seed OpenSSL PRNG with current contents of the screen | |||||
RAND_screen(); | |||||
#endif | |||||
// Seed OpenSSL PRNG with performance counter | |||||
RandAddSeed(); | |||||
} | |||||
~RNGState() { | |||||
// Securely erase the memory used by the OpenSSL PRNG | |||||
RAND_cleanup(); | |||||
// Shutdown OpenSSL library multithreading support | |||||
CRYPTO_set_locking_callback(nullptr); | |||||
} | |||||
/** | /** | ||||
* Extract up to 32 bytes of entropy from the RNG state, mixing in new | * Extract up to 32 bytes of entropy from the RNG state, mixing in new | ||||
* entropy from hasher. | * entropy from hasher. | ||||
*/ | */ | ||||
void MixExtract(uint8_t *out, size_t num, CSHA512 &&hasher) { | void MixExtract(uint8_t *out, size_t num, CSHA512 &&hasher) { | ||||
assert(num <= 32); | assert(num <= 32); | ||||
uint8_t buf[64]; | uint8_t buf[64]; | ||||
Show All 27 Lines | RNGState &GetRNGState() { | ||||
// This C++11 idiom relies on the guarantee that static variable are | // This C++11 idiom relies on the guarantee that static variable are | ||||
// initialized on first call, even when multiple parallel calls are | // initialized on first call, even when multiple parallel calls are | ||||
// permitted. | // permitted. | ||||
static std::unique_ptr<RNGState> g_rng{new RNGState()}; | static std::unique_ptr<RNGState> g_rng{new RNGState()}; | ||||
return *g_rng; | return *g_rng; | ||||
} | } | ||||
} // namespace | } // namespace | ||||
void LockingCallbackOpenSSL(int mode, int i, const char *file, | |||||
int line) NO_THREAD_SAFETY_ANALYSIS { | |||||
RNGState &rng = GetRNGState(); | |||||
if (mode & CRYPTO_LOCK) { | |||||
rng.m_mutex_openssl[i].lock(); | |||||
} else { | |||||
rng.m_mutex_openssl[i].unlock(); | |||||
} | |||||
} | |||||
static void AddDataToRng(void *data, size_t len, RNGState &rng); | static void AddDataToRng(void *data, size_t len, RNGState &rng); | ||||
void RandAddSeedSleep() { | void RandAddSeedSleep() { | ||||
RNGState &rng = GetRNGState(); | RNGState &rng = GetRNGState(); | ||||
int64_t nPerfCounter1 = GetPerformanceCounter(); | int64_t nPerfCounter1 = GetPerformanceCounter(); | ||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||||
int64_t nPerfCounter2 = GetPerformanceCounter(); | int64_t nPerfCounter2 = GetPerformanceCounter(); | ||||
▲ Show 20 Lines • Show All 186 Lines • Show Last 20 Lines |