diff options
Diffstat (limited to 'src/random.cpp')
-rw-r--r-- | src/random.cpp | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/src/random.cpp b/src/random.cpp index 6155c0d8cf..8ad0a9b007 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -5,9 +5,11 @@ #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() @@ -43,7 +45,7 @@ void RandAddSeed() memory_cleanse((void*)&nCounter, sizeof(nCounter)); } -void RandAddSeedPerfmon() +static void RandAddSeedPerfmon() { RandAddSeed(); @@ -83,6 +85,29 @@ 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); + assert(ret); + ret = CryptGenRandom(hProvider, 32, ent32); + assert(ret); + CryptReleaseContext(hProvider, 0); +#else + int f = open("/dev/urandom", O_RDONLY); + assert(f != -1); + int have = 0; + do { + ssize_t n = read(f, ent32 + have, 32 - have); + assert(n > 0 && n <= 32 - have); + have += n; + } while (have < 32); + close(f); +#endif +} + void GetRandBytes(unsigned char* buf, int num) { if (RAND_bytes(buf, num) != 1) { @@ -91,6 +116,27 @@ void GetRandBytes(unsigned char* buf, int num) } } +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) |