]>
Commit | Line | Data |
---|---|---|
6354935c PK |
1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | // Copyright (c) 2009-2014 The Bitcoin developers | |
3 | // Distributed under the MIT/X11 software license, see the accompanying | |
4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
5 | ||
6 | #include "random.h" | |
7 | ||
8 | #ifdef WIN32 | |
9 | #include "compat.h" // for Windows API | |
10 | #endif | |
20e01b1a PW |
11 | #include "serialize.h" // for begin_ptr(vec) |
12 | #include "util.h" // for LogPrint() | |
ad49c256 | 13 | #include "utilstrencodings.h" // for GetTime() |
6354935c | 14 | |
611116d4 PK |
15 | #include <limits> |
16 | ||
6354935c PK |
17 | #ifndef WIN32 |
18 | #include <sys/time.h> | |
19 | #endif | |
611116d4 | 20 | |
6354935c PK |
21 | #include <openssl/crypto.h> |
22 | #include <openssl/err.h> | |
23 | #include <openssl/rand.h> | |
24 | ||
25 | static inline int64_t GetPerformanceCounter() | |
26 | { | |
27 | int64_t nCounter = 0; | |
28 | #ifdef WIN32 | |
29 | QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); | |
30 | #else | |
31 | timeval t; | |
32 | gettimeofday(&t, NULL); | |
33 | nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec); | |
34 | #endif | |
35 | return nCounter; | |
36 | } | |
37 | ||
38 | void RandAddSeed() | |
39 | { | |
40 | // Seed with CPU performance counter | |
41 | int64_t nCounter = GetPerformanceCounter(); | |
42 | RAND_add(&nCounter, sizeof(nCounter), 1.5); | |
4eedf4ff | 43 | OPENSSL_cleanse((void*)&nCounter, sizeof(nCounter)); |
6354935c PK |
44 | } |
45 | ||
46 | void RandAddSeedPerfmon() | |
47 | { | |
48 | RandAddSeed(); | |
49 | ||
50 | // This can take up to 2 seconds, so only do it every 10 minutes | |
51 | static int64_t nLastPerfmon; | |
52 | if (GetTime() < nLastPerfmon + 10 * 60) | |
53 | return; | |
54 | nLastPerfmon = GetTime(); | |
55 | ||
56 | #ifdef WIN32 | |
57 | // Don't need this on Linux, OpenSSL automatically uses /dev/urandom | |
58 | // Seed with the entire set of perfmon data | |
20e01b1a | 59 | std::vector<unsigned char> vData(250000, 0); |
6354935c PK |
60 | long ret = 0; |
61 | unsigned long nSize = 0; | |
62 | const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data | |
20e01b1a | 63 | while (true) { |
6354935c PK |
64 | nSize = vData.size(); |
65 | ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, begin_ptr(vData), &nSize); | |
66 | if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize) | |
67 | break; | |
20e01b1a | 68 | vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially |
6354935c PK |
69 | } |
70 | RegCloseKey(HKEY_PERFORMANCE_DATA); | |
20e01b1a PW |
71 | if (ret == ERROR_SUCCESS) { |
72 | RAND_add(begin_ptr(vData), nSize, nSize / 100.0); | |
6354935c PK |
73 | OPENSSL_cleanse(begin_ptr(vData), nSize); |
74 | LogPrint("rand", "%s: %lu bytes\n", __func__, nSize); | |
75 | } else { | |
76 | static bool warned = false; // Warn only once | |
20e01b1a | 77 | if (!warned) { |
6354935c PK |
78 | LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret); |
79 | warned = true; | |
80 | } | |
81 | } | |
82 | #endif | |
83 | } | |
84 | ||
20e01b1a | 85 | bool GetRandBytes(unsigned char* buf, int num) |
6354935c PK |
86 | { |
87 | if (RAND_bytes(buf, num) != 1) { | |
88 | LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL)); | |
89 | return false; | |
90 | } | |
91 | return true; | |
92 | } | |
93 | ||
94 | uint64_t GetRand(uint64_t nMax) | |
95 | { | |
96 | if (nMax == 0) | |
97 | return 0; | |
98 | ||
99 | // The range of the random source must be a multiple of the modulus | |
100 | // to give every possible output value an equal possibility | |
101 | uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax; | |
102 | uint64_t nRand = 0; | |
103 | do { | |
104 | GetRandBytes((unsigned char*)&nRand, sizeof(nRand)); | |
105 | } while (nRand >= nRange); | |
106 | return (nRand % nMax); | |
107 | } | |
108 | ||
109 | int GetRandInt(int nMax) | |
110 | { | |
111 | return GetRand(nMax); | |
112 | } | |
113 | ||
114 | uint256 GetRandHash() | |
115 | { | |
116 | uint256 hash; | |
117 | GetRandBytes((unsigned char*)&hash, sizeof(hash)); | |
118 | return hash; | |
119 | } | |
120 | ||
121 | uint32_t insecure_rand_Rz = 11; | |
122 | uint32_t insecure_rand_Rw = 11; | |
123 | void seed_insecure_rand(bool fDeterministic) | |
124 | { | |
125 | // The seed values have some unlikely fixed points which we avoid. | |
20e01b1a | 126 | if (fDeterministic) { |
6354935c PK |
127 | insecure_rand_Rz = insecure_rand_Rw = 11; |
128 | } else { | |
129 | uint32_t tmp; | |
130 | do { | |
131 | GetRandBytes((unsigned char*)&tmp, 4); | |
20e01b1a | 132 | } while (tmp == 0 || tmp == 0x9068ffffU); |
6354935c PK |
133 | insecure_rand_Rz = tmp; |
134 | do { | |
135 | GetRandBytes((unsigned char*)&tmp, 4); | |
20e01b1a | 136 | } while (tmp == 0 || tmp == 0x464fffffU); |
6354935c PK |
137 | insecure_rand_Rw = tmp; |
138 | } | |
139 | } |