mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
218 lines
5.1 KiB
C++
218 lines
5.1 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
Copyright (c) 2011-2013, OpenCoin, Inc.
|
|
*/
|
|
//==============================================================================
|
|
|
|
RandomNumbers::RandomNumbers ()
|
|
: m_initialized (false)
|
|
{
|
|
}
|
|
|
|
RandomNumbers::~RandomNumbers ()
|
|
{
|
|
}
|
|
|
|
bool RandomNumbers::initialize ()
|
|
{
|
|
assert (!m_initialized);
|
|
|
|
bool success = platformAddEntropy ();
|
|
|
|
if (success)
|
|
m_initialized = true;
|
|
|
|
return success;
|
|
}
|
|
|
|
void RandomNumbers::fillBytes (void* destinationBuffer, int numberOfBytes)
|
|
{
|
|
// VFALCO NOTE this assert is here to remind us that the code is not yet
|
|
// thread safe.
|
|
assert (m_initialized);
|
|
|
|
// VFALCO NOTE When a spinlock is available in beast, use it here.
|
|
if (! m_initialized)
|
|
{
|
|
if (! initialize ())
|
|
{
|
|
char const* message = "Unable to add system entropy";
|
|
Log::out() << message;
|
|
throw std::runtime_error (message);
|
|
}
|
|
}
|
|
|
|
#ifdef PURIFY
|
|
memset (destinationBuffer, 0, numberOfBytes);
|
|
#endif
|
|
|
|
if (RAND_bytes (reinterpret_cast <unsigned char*> (destinationBuffer), numberOfBytes) != 1)
|
|
{
|
|
assert (false);
|
|
|
|
throw std::runtime_error ("Entropy pool not seeded");
|
|
}
|
|
}
|
|
|
|
RandomNumbers& RandomNumbers::getInstance ()
|
|
{
|
|
static RandomNumbers instance;
|
|
|
|
return instance;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
#if BEAST_WIN32
|
|
|
|
// Get entropy from the Windows crypto provider
|
|
bool RandomNumbers::platformAddEntropy ()
|
|
{
|
|
char name[512], rand[128];
|
|
DWORD count = 500;
|
|
HCRYPTPROV cryptoHandle;
|
|
|
|
if (!CryptGetDefaultProviderA (PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, name, &count))
|
|
{
|
|
#ifdef BEAST_DEBUG
|
|
Log::out() << "Unable to get default crypto provider";
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
if (!CryptAcquireContextA (&cryptoHandle, NULL, name, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
|
{
|
|
#ifdef BEAST_DEBUG
|
|
Log::out() << "Unable to acquire crypto provider";
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
if (!CryptGenRandom (cryptoHandle, 128, reinterpret_cast<BYTE*> (rand)))
|
|
{
|
|
#ifdef BEAST_DEBUG
|
|
Log::out() << "Unable to get entropy from crypto provider";
|
|
#endif
|
|
CryptReleaseContext (cryptoHandle, 0);
|
|
return false;
|
|
}
|
|
|
|
CryptReleaseContext (cryptoHandle, 0);
|
|
RAND_seed (rand, 128);
|
|
|
|
return true;
|
|
}
|
|
|
|
#else
|
|
|
|
bool RandomNumbers::platformAddEntropy ()
|
|
{
|
|
char rand[128];
|
|
std::ifstream reader;
|
|
|
|
reader.open ("/dev/urandom", std::ios::in | std::ios::binary);
|
|
|
|
if (!reader.is_open ())
|
|
{
|
|
#ifdef BEAST_DEBUG
|
|
Log::out() << "Unable to open random source";
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
reader.read (rand, 128);
|
|
|
|
int bytesRead = reader.gcount ();
|
|
|
|
if (bytesRead == 0)
|
|
{
|
|
#ifdef BEAST_DEBUG
|
|
Log::out() << "Unable to read from random source";
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
RAND_seed (rand, bytesRead);
|
|
return bytesRead >= 64;
|
|
}
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
//
|
|
// "Never go to sea with two chronometers; take one or three."
|
|
// Our three time sources are:
|
|
// - System clock
|
|
// - Median of other nodes's clocks
|
|
// - The user (asking the user to fix the system clock if the first two disagree)
|
|
//
|
|
|
|
void RandomNumbers::platformAddPerformanceMonitorEntropy ()
|
|
{
|
|
// VFALCO TODO Remove all this fancy stuff
|
|
struct
|
|
{
|
|
int64 operator () () const
|
|
{
|
|
return time (NULL);
|
|
}
|
|
} GetTime;
|
|
|
|
struct
|
|
{
|
|
void operator () ()
|
|
{
|
|
struct
|
|
{
|
|
// VFALCO TODO clean this up
|
|
int64 operator () () const
|
|
{
|
|
int64 nCounter = 0;
|
|
#if BEAST_WIN32
|
|
QueryPerformanceCounter ((LARGE_INTEGER*)&nCounter);
|
|
#else
|
|
timeval t;
|
|
gettimeofday (&t, NULL);
|
|
nCounter = t.tv_sec * 1000000 + t.tv_usec;
|
|
#endif
|
|
return nCounter;
|
|
}
|
|
} GetPerformanceCounter;
|
|
|
|
// Seed with CPU performance counter
|
|
int64 nCounter = GetPerformanceCounter ();
|
|
RAND_add (&nCounter, sizeof (nCounter), 1.5);
|
|
memset (&nCounter, 0, sizeof (nCounter));
|
|
}
|
|
} RandAddSeed;
|
|
|
|
RandAddSeed ();
|
|
|
|
// This can take up to 2 seconds, so only do it every 10 minutes
|
|
static int64 nLastPerfmon;
|
|
|
|
if (GetTime () < nLastPerfmon + 10 * 60)
|
|
return;
|
|
|
|
nLastPerfmon = GetTime ();
|
|
|
|
#if BEAST_WIN32
|
|
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
|
|
// Seed with the entire set of perfmon data
|
|
unsigned char pdata[250000];
|
|
memset (pdata, 0, sizeof (pdata));
|
|
unsigned long nSize = sizeof (pdata);
|
|
long ret = RegQueryValueExA (HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
|
|
RegCloseKey (HKEY_PERFORMANCE_DATA);
|
|
|
|
if (ret == ERROR_SUCCESS)
|
|
{
|
|
RAND_add (pdata, nSize, nSize / 100.0);
|
|
memset (pdata, 0, nSize);
|
|
//printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
|
|
}
|
|
|
|
#endif
|
|
}
|