aboutsummaryrefslogtreecommitdiff
path: root/src/random.cpp
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2016-08-09 05:45:50 +0000
committerLuke Dashjr <luke-jr+git@utopios.org>2016-08-09 05:45:50 +0000
commitdf634908ba758232413c50e8f1f7a80d546d777b (patch)
tree92cccae378b192f5f70986d2167209cbfd24ae08 /src/random.cpp
parente98e3dde6a976a2c8f266ee963d6931fd4b37262 (diff)
parente4382fbef56a0e04b0ed834e8b3a3a16f81db149 (diff)
downloadbitcoin-df634908ba758232413c50e8f1f7a80d546d777b.tar.xz
Merge tag 'branch-0.13' into bugfix_gitdir
Diffstat (limited to 'src/random.cpp')
-rw-r--r--src/random.cpp83
1 files changed, 72 insertions, 11 deletions
diff --git a/src/random.cpp b/src/random.cpp
index fc9505ae73..d9a8cc145e 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -1,27 +1,36 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#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
#include <sys/time.h>
#endif
-#include <openssl/crypto.h>
#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;
@@ -40,22 +49,23 @@ void RandAddSeed()
// Seed with CPU performance counter
int64_t nCounter = GetPerformanceCounter();
RAND_add(&nCounter, sizeof(nCounter), 1.5);
- OPENSSL_cleanse((void*)&nCounter, sizeof(nCounter));
+ memory_cleanse((void*)&nCounter, sizeof(nCounter));
}
-void RandAddSeedPerfmon()
+static void RandAddSeedPerfmon()
{
RandAddSeed();
+#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();
-#ifdef WIN32
- // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
- // Seed with the entire set of perfmon data
std::vector<unsigned char> vData(250000, 0);
long ret = 0;
unsigned long nSize = 0;
@@ -70,7 +80,7 @@ void RandAddSeedPerfmon()
RegCloseKey(HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS) {
RAND_add(begin_ptr(vData), nSize, nSize / 100.0);
- OPENSSL_cleanse(begin_ptr(vData), nSize);
+ memory_cleanse(begin_ptr(vData), nSize);
LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
} else {
static bool warned = false; // Warn only once
@@ -82,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)