Skip to content

Commit

Permalink
Remove deprecated random number generator functions
Browse files Browse the repository at this point in the history
This commit changes CInit to check for proper RNG seeding and use
RAND_poll() if necessary.

It removes RandAddSeed() RandAddSeedPerfmon() and also the use
of RAND_screen.
  • Loading branch information
jamescowens committed Aug 15, 2021
1 parent 6f2b2df commit 723a2f9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 17 deletions.
10 changes: 0 additions & 10 deletions src/qt/winshutdownmonitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,6 @@ bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void *pM

MSG *pMsg = static_cast<MSG *>(pMessage);

// Seed OpenSSL PRNG with Windows event data (e.g. mouse movements and other user interactions)
if (RAND_event(pMsg->message, pMsg->wParam, pMsg->lParam) == 0) {
// Warn only once as this is performance-critical
static bool warned = false;
if (!warned) {
LogPrintf("%s: OpenSSL RAND_event() failed to seed OpenSSL PRNG with enough data.\n", __func__);
warned = true;
}
}

switch(pMsg->message)
{
case WM_QUERYENDSESSION:
Expand Down
38 changes: 31 additions & 7 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,36 @@ class CInit
ppmutexOpenSSL[i] = new CCriticalSection();
CRYPTO_set_locking_callback(locking_callback);

#ifdef WIN32
// Seed OpenSSL PRNG with current contents of the screen
RAND_screen();
#endif
// Check whether OpenSSL random number generator is properly seeded. If not, attempt to seed using RAND_poll().
// Note that in versions of OpenSSL in the depends in Gridcoin (currently 1.1.1+), and modern Unix distros (using
// openSSL 1.1+ or modern Windows operating systems with the equivalent of /dev/urandom, the random number
// generator is automatically seeded on init, and periodically reseeded from trusted OS random sources. It is
// not necessary to manually reseed the RNG. Here we implement a check via RAND_status() to ensure the RNG
// is properly seeded. If not, we try 10 times (probably excessive) to seed the RNG via openSSL's entropy sources,
// breaking as soon as the return from RAND_poll() becomes 1 (successfully seeded). A 100 ms sleep is inserted
// between each try to ensure we give time for a short term unavailability of the OS entropy source to recover.
// If this falls through, we abort the application as we cannot have a non-functioning RNG.
bool seed_successful = RAND_status();
if (!seed_successful) {
for (unsigned int i = 0; i < 10; ++i)
{
seed_successful = RAND_poll();

if (seed_successful) break;

MilliSleep(100);
}

// Seed OpenSSL PRNG with performance counter
RandAddSeed();
if (!seed_successful) {
tfm::format(std::cerr, "ERROR: %s: Unable to initialize the random number generator. Cannot continue. "
"Please check your operating system to ensure the random number source is "
"available. (This is /dev/urandom on Linux.)",
__func__);
std::abort();
}
}
}

~CInit()
{
// Securely erase the memory used by the PRNG
Expand All @@ -118,13 +140,15 @@ void RandAddSeedPerfmon()
{
RandAddSeed();

// Only need for OpenSSL < 1.1 and Win32, since 1.1 and greater seed properly from Windows, and on Linux seeds properly
// in all cases.
#if OPENSSL_VERSION_NUMBER < 0x10100000L && defined(WIN32)
// This can take up to 2 seconds, so only do it every 10 minutes
static int64_t nLastPerfmon;
if ( GetAdjustedTime() < nLastPerfmon + 10 * 60)
return;
nLastPerfmon = GetAdjustedTime();

#ifdef WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
unsigned char pdata[250000];
Expand Down

0 comments on commit 723a2f9

Please sign in to comment.