| 63 | namespace { |
| 64 | |
| 65 | void RandAddSeedPerfmon(CSHA512& hasher) |
| 66 | { |
| 67 | #ifdef WIN32 |
| 68 | // Seed with the entire set of perfmon data |
| 69 | |
| 70 | // This can take up to 2 seconds, so only do it every 10 minutes. |
| 71 | // Initialize last_perfmon to 0 seconds, we don't skip the first call. |
| 72 | static std::atomic<std::chrono::seconds> last_perfmon{0s}; |
| 73 | auto last_time = last_perfmon.load(); |
| 74 | auto current_time = GetTime<std::chrono::seconds>(); |
| 75 | if (current_time < last_time + std::chrono::minutes{10}) return; |
| 76 | last_perfmon = current_time; |
| 77 | |
| 78 | std::vector<unsigned char> vData(250000, 0); |
| 79 | long ret = 0; |
| 80 | unsigned long nSize = 0; |
| 81 | const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data |
| 82 | while (true) { |
| 83 | nSize = vData.size(); |
| 84 | ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", nullptr, nullptr, vData.data(), &nSize); |
| 85 | if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize) |
| 86 | break; |
| 87 | vData.resize(std::min((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially |
| 88 | } |
| 89 | RegCloseKey(HKEY_PERFORMANCE_DATA); |
| 90 | if (ret == ERROR_SUCCESS) { |
| 91 | hasher.Write(vData.data(), nSize); |
| 92 | memory_cleanse(vData.data(), nSize); |
| 93 | } else { |
| 94 | // Performance data is only a best-effort attempt at improving the |
| 95 | // situation when the OS randomness (and other sources) aren't |
| 96 | // adequate. As a result, failure to read it is isn't considered critical, |
| 97 | // so we don't call RandFailure(). |
| 98 | // TODO: Add logging when the logger is made functional before global |
| 99 | // constructors have been invoked. |
| 100 | } |
| 101 | #endif |
| 102 | } |
| 103 | |
| 104 | /** Helper to easily feed data into a CSHA512. |
| 105 | * |
no test coverage detected