Skip to content

Commit

Permalink
Merge bitcoin#7891: Always require OS randomness when generating secr…
Browse files Browse the repository at this point in the history
…et keys

628cf14 Don't use assert for catching randomness failures (Pieter Wuille)
fa2637a Always require OS randomness when generating secret keys (Pieter Wuille)
  • Loading branch information
sipa authored and codablock committed Dec 21, 2017
1 parent cee571b commit 43cbeb7
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/Makefile.am
Expand Up @@ -469,7 +469,8 @@ endif
dash_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL)
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO)
dash_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
#

Expand Down
2 changes: 0 additions & 2 deletions src/init.cpp
Expand Up @@ -1781,8 +1781,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!strErrors.str().empty())
return InitError(strErrors.str());

RandAddSeedPerfmon();

//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("chainActive.Height() = %d\n", chainActive.Height());
Expand Down
3 changes: 1 addition & 2 deletions src/keepass.cpp
Expand Up @@ -232,8 +232,7 @@ SecureString CKeePassIntegrator::generateRandomKey(size_t nSize)
SecureString sKey;
sKey.resize(nSize);

RandAddSeedPerfmon();
GetRandBytes((unsigned char *) &sKey[0], nSize);
GetStrongRandBytes((unsigned char *) &sKey[0], nSize);

return sKey;
}
Expand Down
3 changes: 1 addition & 2 deletions src/key.cpp
Expand Up @@ -124,9 +124,8 @@ bool CKey::Check(const unsigned char *vch) {
}

void CKey::MakeNewKey(bool fCompressedIn) {
RandAddSeedPerfmon();
do {
GetRandBytes(vch, sizeof(vch));
GetStrongRandBytes(vch, sizeof(vch));
} while (!Check(vch));
fValid = true;
fCompressed = fCompressedIn;
Expand Down
2 changes: 0 additions & 2 deletions src/net_processing.cpp
Expand Up @@ -1076,8 +1076,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam

bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, std::atomic<bool>& interruptMsgProc)
{
RandAddSeedPerfmon();

LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);

if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
Expand Down
66 changes: 63 additions & 3 deletions src/random.cpp
Expand Up @@ -5,14 +5,17 @@

#include "random.h"

#include "crypto/sha512.h"
#include "support/cleanse.h"
#ifdef WIN32
#include "compat.h" // for Windows API
#include <wincrypt.h>
#endif
#include "serialize.h" // for begin_ptr(vec)
#include "util.h" // for LogPrint()
#include "utilstrencodings.h" // for GetTime()

#include <stdlib.h>
#include <limits>

#ifndef WIN32
Expand All @@ -22,6 +25,12 @@
#include <openssl/err.h>
#include <openssl/rand.h>

static void RandFailure()
{
LogPrintf("Failed to read randomness, aborting\n");
abort();
}

static inline int64_t GetPerformanceCounter()
{
int64_t nCounter = 0;
Expand All @@ -43,7 +52,7 @@ void RandAddSeed()
memory_cleanse((void*)&nCounter, sizeof(nCounter));
}

void RandAddSeedPerfmon()
static void RandAddSeedPerfmon()
{
RandAddSeed();

Expand Down Expand Up @@ -83,14 +92,65 @@ void RandAddSeedPerfmon()
#endif
}

/** Get 32 bytes of system entropy. */
static void GetOSRand(unsigned char *ent32)
{
#ifdef WIN32
HCRYPTPROV hProvider;
int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if (!ret) {
RandFailure();
}
ret = CryptGenRandom(hProvider, 32, ent32);
if (!ret) {
RandFailure();
}
CryptReleaseContext(hProvider, 0);
#else
int f = open("/dev/urandom", O_RDONLY);
if (f == -1) {
RandFailure();
}
int have = 0;
do {
ssize_t n = read(f, ent32 + have, 32 - have);
if (n <= 0 || n + have > 32) {
RandFailure();
}
have += n;
} while (have < 32);
close(f);
#endif
}

void GetRandBytes(unsigned char* buf, int num)
{
if (RAND_bytes(buf, num) != 1) {
LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL));
assert(false);
RandFailure();
}
}

void GetStrongRandBytes(unsigned char* out, int num)
{
assert(num <= 32);
CSHA512 hasher;
unsigned char buf[64];

// First source: OpenSSL's RNG
RandAddSeedPerfmon();
GetRandBytes(buf, 32);
hasher.Write(buf, 32);

// Second source: OS RNG
GetOSRand(buf);
hasher.Write(buf, 32);

// Produce output
hasher.Finalize(buf);
memcpy(out, buf, num);
memory_cleanse(buf, 64);
}

uint64_t GetRand(uint64_t nMax)
{
if (nMax == 0)
Expand Down
11 changes: 7 additions & 4 deletions src/random.h
Expand Up @@ -10,11 +10,8 @@

#include <stdint.h>

/**
* Seed OpenSSL PRNG with additional entropy data
*/
/* Seed OpenSSL PRNG with additional entropy data */
void RandAddSeed();
void RandAddSeedPerfmon();

/**
* Functions to gather random data via the OpenSSL PRNG
Expand All @@ -24,6 +21,12 @@ uint64_t GetRand(uint64_t nMax);
int GetRandInt(int nMax);
uint256 GetRandHash();

/**
* Function to gather random data from multiple sources, failing whenever any
* of those source fail to provide a result.
*/
void GetStrongRandBytes(unsigned char* buf, int num);

/**
* Seed insecure_rand using the random pool.
* @param Deterministic Use a deterministic seed
Expand Down
8 changes: 2 additions & 6 deletions src/wallet/wallet.cpp
Expand Up @@ -738,16 +738,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return false;

CKeyingMaterial vMasterKey;
RandAddSeedPerfmon();

vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);

CMasterKey kMasterKey;
RandAddSeedPerfmon();

kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);

This comment has been minimized.

Copy link
@Ri2k18

Ri2k18 Sep 16, 2018

tring "01"; "02"; "03"; "04"; "05"; "06"; "07" print =a+@b


CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
Expand Down Expand Up @@ -4549,8 +4547,6 @@ bool CWallet::InitLoadWallet()
if (fFirstRun)
{
// Create new keyUser and set as default key
RandAddSeedPerfmon();

if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
if (GetArg("-mnemonicpassphrase", "").size() > 256) {
return InitError(_("Mnemonic passphrase is too long, must be at most 256 characters"));
Expand Down

0 comments on commit 43cbeb7

Please sign in to comment.