Dogecoin Core  1.14.2
P2P Digital Currency
random.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "random.h"
7 
8 #include "crypto/sha512.h"
9 #include "support/cleanse.h"
10 #ifdef WIN32
11 #include "compat.h" // for Windows API
12 #include <wincrypt.h>
13 #endif
14 #include "util.h" // for LogPrint()
15 #include "utilstrencodings.h" // for GetTime()
16 
17 #include <stdlib.h>
18 #include <limits>
19 
20 #ifndef WIN32
21 #include <sys/time.h>
22 #endif
23 
24 #include <openssl/err.h>
25 #include <openssl/rand.h>
26 
27 static void RandFailure()
28 {
29  LogPrintf("Failed to read randomness, aborting\n");
30  abort();
31 }
32 
33 static inline int64_t GetPerformanceCounter()
34 {
35  int64_t nCounter = 0;
36 #ifdef WIN32
37  QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
38 #else
39  timeval t;
40  gettimeofday(&t, NULL);
41  nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
42 #endif
43  return nCounter;
44 }
45 
47 {
48  // Seed with CPU performance counter
49  int64_t nCounter = GetPerformanceCounter();
50  RAND_add(&nCounter, sizeof(nCounter), 1.5);
51  memory_cleanse((void*)&nCounter, sizeof(nCounter));
52 }
53 
54 static void RandAddSeedPerfmon()
55 {
56  RandAddSeed();
57 
58 #ifdef WIN32
59  // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
60  // Seed with the entire set of perfmon data
61 
62  // This can take up to 2 seconds, so only do it every 10 minutes
63  static int64_t nLastPerfmon;
64  if (GetTime() < nLastPerfmon + 10 * 60)
65  return;
66  nLastPerfmon = GetTime();
67 
68  std::vector<unsigned char> vData(250000, 0);
69  long ret = 0;
70  unsigned long nSize = 0;
71  const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
72  while (true) {
73  nSize = vData.size();
74  ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, vData.data(), &nSize);
75  if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
76  break;
77  vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially
78  }
79  RegCloseKey(HKEY_PERFORMANCE_DATA);
80  if (ret == ERROR_SUCCESS) {
81  RAND_add(vData.data(), nSize, nSize / 100.0);
82  memory_cleanse(vData.data(), nSize);
83  LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
84  } else {
85  static bool warned = false; // Warn only once
86  if (!warned) {
87  LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret);
88  warned = true;
89  }
90  }
91 #endif
92 }
93 
95 static void GetOSRand(unsigned char *ent32)
96 {
97 #ifdef WIN32
98  HCRYPTPROV hProvider;
99  int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
100  if (!ret) {
101  RandFailure();
102  }
103  ret = CryptGenRandom(hProvider, 32, ent32);
104  if (!ret) {
105  RandFailure();
106  }
107  CryptReleaseContext(hProvider, 0);
108 #else
109  int f = open("/dev/urandom", O_RDONLY);
110  if (f == -1) {
111  RandFailure();
112  }
113  int have = 0;
114  do {
115  ssize_t n = read(f, ent32 + have, 32 - have);
116  if (n <= 0 || n + have > 32) {
117  RandFailure();
118  }
119  have += n;
120  } while (have < 32);
121  close(f);
122 #endif
123 }
124 
125 void GetRandBytes(unsigned char* buf, int num)
126 {
127  if (RAND_bytes(buf, num) != 1) {
128  RandFailure();
129  }
130 }
131 
132 void GetStrongRandBytes(unsigned char* out, int num)
133 {
134  assert(num <= 32);
135  CSHA512 hasher;
136  unsigned char buf[64];
137 
138  // First source: OpenSSL's RNG
139  RandAddSeedPerfmon();
140  GetRandBytes(buf, 32);
141  hasher.Write(buf, 32);
142 
143  // Second source: OS RNG
144  GetOSRand(buf);
145  hasher.Write(buf, 32);
146 
147  // Produce output
148  hasher.Finalize(buf);
149  memcpy(out, buf, num);
150  memory_cleanse(buf, 64);
151 }
152 
153 uint64_t GetRand(uint64_t nMax)
154 {
155  if (nMax == 0)
156  return 0;
157 
158  // The range of the random source must be a multiple of the modulus
159  // to give every possible output value an equal possibility
160  uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
161  uint64_t nRand = 0;
162  do {
163  GetRandBytes((unsigned char*)&nRand, sizeof(nRand));
164  } while (nRand >= nRange);
165  return (nRand % nMax);
166 }
167 
168 int GetRandInt(int nMax)
169 {
170  return GetRand(nMax);
171 }
172 
174 {
175  uint256 hash;
176  GetRandBytes((unsigned char*)&hash, sizeof(hash));
177  return hash;
178 }
179 
181 {
182  // The seed values have some unlikely fixed points which we avoid.
183  if (fDeterministic) {
184  Rz = Rw = 11;
185  } else {
186  uint32_t tmp;
187  do {
188  GetRandBytes((unsigned char*)&tmp, 4);
189  } while (tmp == 0 || tmp == 0x9068ffffU);
190  Rz = tmp;
191  do {
192  GetRandBytes((unsigned char*)&tmp, 4);
193  } while (tmp == 0 || tmp == 0x464fffffU);
194  Rw = tmp;
195  }
196 }
197 
A hasher class for SHA-512.
Definition: sha512.h:13
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: sha512.cpp:185
CSHA512 & Write(const unsigned char *data, size_t len)
Definition: sha512.cpp:159
FastRandomContext(bool fDeterministic=false)
Definition: random.cpp:180
uint32_t Rw
Definition: random.h:46
uint32_t Rz
Definition: random.h:45
256-bit opaque blob.
Definition: uint256.h:123
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:10
void * memcpy(void *a, const void *b, size_t c)
int GetRandInt(int nMax)
Definition: random.cpp:168
uint64_t GetRand(uint64_t nMax)
Definition: random.cpp:153
void RandAddSeed()
Definition: random.cpp:46
void GetStrongRandBytes(unsigned char *out, int num)
Function to gather random data from multiple sources, failing whenever any of those source fail to pr...
Definition: random.cpp:132
void GetRandBytes(unsigned char *buf, int num)
Functions to gather random data via the OpenSSL PRNG.
Definition: random.cpp:125
uint256 GetRandHash()
Definition: random.cpp:173
#define LogPrint(category,...)
Definition: util.h:76
#define LogPrintf(...)
Definition: util.h:82
int64_t GetTime()
GetTimeMicros() and GetTimeMillis() both return the system time, but in different units.
Definition: utiltime.cpp:19