Skip to content

Commit 950be19

Browse files
committed
Merge #7891: Always require OS randomness when generating secret keys
628cf14 Don't use assert for catching randomness failures (Pieter Wuille) fa2637a Always require OS randomness when generating secret keys (Pieter Wuille)
2 parents 52b803e + 628cf14 commit 950be19

File tree

7 files changed

+75
-19
lines changed

7 files changed

+75
-19
lines changed

src/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,8 @@ endif
374374
bitcoin_cli_LDADD = \
375375
$(LIBBITCOIN_CLI) \
376376
$(LIBUNIVALUE) \
377-
$(LIBBITCOIN_UTIL)
377+
$(LIBBITCOIN_UTIL) \
378+
$(LIBBITCOIN_CRYPTO)
378379

379380
bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
380381
#

src/init.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,8 +1401,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
14011401
if (!strErrors.str().empty())
14021402
return InitError(strErrors.str());
14031403

1404-
RandAddSeedPerfmon();
1405-
14061404
//// debug print
14071405
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
14081406
LogPrintf("nBestHeight = %d\n", chainActive.Height());

src/key.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,8 @@ bool CKey::Check(const unsigned char *vch) {
124124
}
125125

126126
void CKey::MakeNewKey(bool fCompressedIn) {
127-
RandAddSeedPerfmon();
128127
do {
129-
GetRandBytes(vch, sizeof(vch));
128+
GetStrongRandBytes(vch, sizeof(vch));
130129
} while (!Check(vch));
131130
fValid = true;
132131
fCompressed = fCompressedIn;

src/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4547,7 +4547,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
45474547

45484548
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
45494549
{
4550-
RandAddSeedPerfmon();
45514550
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
45524551
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
45534552
{

src/random.cpp

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55

66
#include "random.h"
77

8+
#include "crypto/sha512.h"
89
#include "support/cleanse.h"
910
#ifdef WIN32
1011
#include "compat.h" // for Windows API
12+
#include <wincrypt.h>
1113
#endif
1214
#include "serialize.h" // for begin_ptr(vec)
1315
#include "util.h" // for LogPrint()
1416
#include "utilstrencodings.h" // for GetTime()
1517

18+
#include <stdlib.h>
1619
#include <limits>
1720

1821
#ifndef WIN32
@@ -22,6 +25,12 @@
2225
#include <openssl/err.h>
2326
#include <openssl/rand.h>
2427

28+
static void RandFailure()
29+
{
30+
LogPrintf("Failed to read randomness, aborting\n");
31+
abort();
32+
}
33+
2534
static inline int64_t GetPerformanceCounter()
2635
{
2736
int64_t nCounter = 0;
@@ -43,7 +52,7 @@ void RandAddSeed()
4352
memory_cleanse((void*)&nCounter, sizeof(nCounter));
4453
}
4554

46-
void RandAddSeedPerfmon()
55+
static void RandAddSeedPerfmon()
4756
{
4857
RandAddSeed();
4958

@@ -83,14 +92,65 @@ void RandAddSeedPerfmon()
8392
#endif
8493
}
8594

95+
/** Get 32 bytes of system entropy. */
96+
static void GetOSRand(unsigned char *ent32)
97+
{
98+
#ifdef WIN32
99+
HCRYPTPROV hProvider;
100+
int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
101+
if (!ret) {
102+
RandFailure();
103+
}
104+
ret = CryptGenRandom(hProvider, 32, ent32);
105+
if (!ret) {
106+
RandFailure();
107+
}
108+
CryptReleaseContext(hProvider, 0);
109+
#else
110+
int f = open("/dev/urandom", O_RDONLY);
111+
if (f == -1) {
112+
RandFailure();
113+
}
114+
int have = 0;
115+
do {
116+
ssize_t n = read(f, ent32 + have, 32 - have);
117+
if (n <= 0 || n + have > 32) {
118+
RandFailure();
119+
}
120+
have += n;
121+
} while (have < 32);
122+
close(f);
123+
#endif
124+
}
125+
86126
void GetRandBytes(unsigned char* buf, int num)
87127
{
88128
if (RAND_bytes(buf, num) != 1) {
89-
LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL));
90-
assert(false);
129+
RandFailure();
91130
}
92131
}
93132

133+
void GetStrongRandBytes(unsigned char* out, int num)
134+
{
135+
assert(num <= 32);
136+
CSHA512 hasher;
137+
unsigned char buf[64];
138+
139+
// First source: OpenSSL's RNG
140+
RandAddSeedPerfmon();
141+
GetRandBytes(buf, 32);
142+
hasher.Write(buf, 32);
143+
144+
// Second source: OS RNG
145+
GetOSRand(buf);
146+
hasher.Write(buf, 32);
147+
148+
// Produce output
149+
hasher.Finalize(buf);
150+
memcpy(out, buf, num);
151+
memory_cleanse(buf, 64);
152+
}
153+
94154
uint64_t GetRand(uint64_t nMax)
95155
{
96156
if (nMax == 0)

src/random.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010

1111
#include <stdint.h>
1212

13-
/**
14-
* Seed OpenSSL PRNG with additional entropy data
15-
*/
13+
/* Seed OpenSSL PRNG with additional entropy data */
1614
void RandAddSeed();
17-
void RandAddSeedPerfmon();
1815

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

24+
/**
25+
* Function to gather random data from multiple sources, failing whenever any
26+
* of those source fail to provide a result.
27+
*/
28+
void GetStrongRandBytes(unsigned char* buf, int num);
29+
2730
/**
2831
* Seed insecure_rand using the random pool.
2932
* @param Deterministic Use a deterministic seed

src/wallet/wallet.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,16 +509,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
509509
return false;
510510

511511
CKeyingMaterial vMasterKey;
512-
RandAddSeedPerfmon();
513512

514513
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
515-
GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
514+
GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
516515

517516
CMasterKey kMasterKey;
518-
RandAddSeedPerfmon();
519517

520518
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
521-
GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
519+
GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
522520

523521
CCrypter crypter;
524522
int64_t nStartTime = GetTimeMillis();
@@ -3147,8 +3145,6 @@ bool CWallet::InitLoadWallet()
31473145
if (fFirstRun)
31483146
{
31493147
// Create new keyUser and set as default key
3150-
RandAddSeedPerfmon();
3151-
31523148
CPubKey newDefaultKey;
31533149
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
31543150
walletInstance->SetDefaultKey(newDefaultKey);

0 commit comments

Comments
 (0)