Changeset View
Changeset View
Standalone View
Standalone View
src/random.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <random.h> | #include <random.h> | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
#include <compat.h> // for Windows API | #include <compat.h> // for Windows API | ||||
#include <wincrypt.h> | #include <wincrypt.h> | ||||
#endif | #endif | ||||
#include <crypto/sha512.h> | #include <crypto/sha512.h> | ||||
#include <logging.h> // for LogPrintf() | #include <logging.h> // for LogPrintf() | ||||
#include <randomenv.h> | |||||
#include <support/allocators/secure.h> | #include <support/allocators/secure.h> | ||||
#include <support/cleanse.h> | #include <support/cleanse.h> | ||||
#include <sync.h> // for Mutex | #include <sync.h> // for Mutex | ||||
#include <util/time.h> // for GetTime() | #include <util/time.h> // for GetTime() | ||||
#include <openssl/conf.h> | #include <openssl/conf.h> | ||||
#include <openssl/err.h> | #include <openssl/err.h> | ||||
#include <openssl/rand.h> | #include <openssl/rand.h> | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | static void Strengthen(const uint8_t (&seed)[32], int microseconds, | ||||
// Produce output from inner state and feed it to outer hasher. | // Produce output from inner state and feed it to outer hasher. | ||||
inner_hasher.Finalize(buffer); | inner_hasher.Finalize(buffer); | ||||
hasher.Write(buffer, sizeof(buffer)); | hasher.Write(buffer, sizeof(buffer)); | ||||
// Try to clean up. | // Try to clean up. | ||||
inner_hasher.Reset(); | inner_hasher.Reset(); | ||||
memory_cleanse(buffer, sizeof(buffer)); | memory_cleanse(buffer, sizeof(buffer)); | ||||
} | } | ||||
static void RandAddSeedPerfmon(CSHA512 &hasher) { | |||||
#ifdef WIN32 | |||||
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom | |||||
// Seed with the entire set of perfmon data | |||||
// This can take up to 2 seconds, so only do it every 10 minutes | |||||
static int64_t nLastPerfmon; | |||||
if (GetTime() < nLastPerfmon + 10 * 60) { | |||||
return; | |||||
} | |||||
nLastPerfmon = GetTime(); | |||||
std::vector<uint8_t> vData(250000, 0); | |||||
long ret = 0; | |||||
unsigned long nSize = 0; | |||||
// Bail out at more than 10MB of performance data | |||||
const size_t nMaxSize = 10000000; | |||||
while (true) { | |||||
nSize = vData.size(); | |||||
ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", nullptr, | |||||
nullptr, vData.data(), &nSize); | |||||
if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize) { | |||||
break; | |||||
} | |||||
// Grow size of buffer exponentially | |||||
vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); | |||||
} | |||||
RegCloseKey(HKEY_PERFORMANCE_DATA); | |||||
if (ret == ERROR_SUCCESS) { | |||||
hasher.Write(vData.data(), nSize); | |||||
memory_cleanse(vData.data(), nSize); | |||||
} else { | |||||
// Performance data is only a best-effort attempt at improving the | |||||
// situation when the OS randomness (and other sources) aren't | |||||
// adequate. As a result, failure to read it is isn't considered | |||||
// critical, so we don't call RandFailure(). | |||||
// TODO: Add logging when the logger is made functional before global | |||||
// constructors have been invoked. | |||||
} | |||||
#endif | |||||
} | |||||
#ifndef WIN32 | #ifndef WIN32 | ||||
/** | /** | ||||
* Fallback: get 32 bytes of system entropy from /dev/urandom. The most | * Fallback: get 32 bytes of system entropy from /dev/urandom. The most | ||||
* compatible way to get cryptographic randomness on UNIX-ish platforms. | * compatible way to get cryptographic randomness on UNIX-ish platforms. | ||||
*/ | */ | ||||
static void GetDevURandom(uint8_t *ent32) { | static void GetDevURandom(uint8_t *ent32) { | ||||
int f = open("/dev/urandom", O_RDONLY); | int f = open("/dev/urandom", O_RDONLY); | ||||
if (f == -1) { | if (f == -1) { | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | static void SeedSleep(CSHA512 &hasher, RNGState &rng) { | ||||
// Sleep for 1ms | // Sleep for 1ms | ||||
MilliSleep(1); | MilliSleep(1); | ||||
// High-precision timestamp after sleeping (as we commit to both the time | // High-precision timestamp after sleeping (as we commit to both the time | ||||
// before and after, this measures the delay) | // before and after, this measures the delay) | ||||
SeedTimestamp(hasher); | SeedTimestamp(hasher); | ||||
// Windows performance monitor data (once every 10 minutes) | // Dynamic environment data (performance monitoring, ...; once every 10 | ||||
RandAddSeedPerfmon(hasher); | // minutes) | ||||
RandAddDynamicEnv(hasher); | |||||
// Strengthen | // Strengthen | ||||
SeedStrengthen(hasher, rng); | SeedStrengthen(hasher, rng); | ||||
} | } | ||||
static void SeedStartup(CSHA512 &hasher, RNGState &rng) noexcept { | static void SeedStartup(CSHA512 &hasher, RNGState &rng) noexcept { | ||||
// Gather 256 bits of hardware randomness, if available | // Gather 256 bits of hardware randomness, if available | ||||
SeedHardwareSlow(hasher); | SeedHardwareSlow(hasher); | ||||
// Everything that the 'slow' seeder includes. | // Everything that the 'slow' seeder includes. | ||||
SeedSlow(hasher); | SeedSlow(hasher); | ||||
// Windows performance monitor data. | // Dynamic environment data | ||||
RandAddSeedPerfmon(hasher); | RandAddDynamicEnv(hasher); | ||||
// Static environment data | |||||
RandAddStaticEnv(hasher); | |||||
// Strengthen | // Strengthen | ||||
SeedStrengthen(hasher, rng); | SeedStrengthen(hasher, rng); | ||||
} | } | ||||
enum class RNGLevel { | enum class RNGLevel { | ||||
FAST, //!< Automatically called by GetRandBytes | FAST, //!< Automatically called by GetRandBytes | ||||
SLOW, //!< Automatically called by GetStrongRandBytes | SLOW, //!< Automatically called by GetStrongRandBytes | ||||
▲ Show 20 Lines • Show All 190 Lines • Show Last 20 Lines |