mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
[Support,Windows] Tolerate failure of CryptGenRandom
Summary: In `Unix/Process.inc`, we seed a random number generator from `/dev/urandom` if possible, but if not, we're happy to fall back to ordinary pseudorandom strategies, like the current time and PID. The corresponding function on Windows calls `CryptGenRandom`, but it //doesn't// have a fallback if that strategy fails. But `CryptGenRandom` //can// fail, if a cryptography provider isn't properly initialized, or occasionally (by our observation) simply intermittently. If it's reasonable on Unix to implement traditional pseudorandom-number seeding as a fallback, then it's surely reasonable to do the same on Windows. So this patch adds a last-ditch use of ordinary rand(), using much the same strategy as the Unix fallback code. Reviewers: hans, sammccall Reviewed By: hans Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77553
This commit is contained in:
parent
e102b60201
commit
fbe3be181d
@ -439,18 +439,38 @@ const char *Process::ResetColor() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Process::GetRandomNumber() {
|
||||
HCRYPTPROV HCPC;
|
||||
if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
ReportLastErrorFatal("Could not acquire a cryptographic context");
|
||||
static unsigned GetRandomNumberSeed() {
|
||||
// Generate a random number seed from the millisecond-resolution Windows
|
||||
// system clock and the current process id.
|
||||
FILETIME Time;
|
||||
GetSystemTimeAsFileTime(&Time);
|
||||
DWORD Pid = GetCurrentProcessId();
|
||||
return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid);
|
||||
}
|
||||
|
||||
ScopedCryptContext CryptoProvider(HCPC);
|
||||
unsigned Ret;
|
||||
if (!::CryptGenRandom(CryptoProvider, sizeof(Ret),
|
||||
reinterpret_cast<BYTE *>(&Ret)))
|
||||
ReportLastErrorFatal("Could not generate a random number");
|
||||
return Ret;
|
||||
static unsigned GetPseudoRandomNumber() {
|
||||
// Arrange to call srand once when this function is first used, and
|
||||
// otherwise (if GetRandomNumber always succeeds in using
|
||||
// CryptGenRandom) don't bother at all.
|
||||
static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);
|
||||
(void)x;
|
||||
return ::rand();
|
||||
}
|
||||
|
||||
unsigned Process::GetRandomNumber() {
|
||||
// Try to use CryptGenRandom.
|
||||
HCRYPTPROV HCPC;
|
||||
if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
ScopedCryptContext CryptoProvider(HCPC);
|
||||
unsigned Ret;
|
||||
if (::CryptGenRandom(CryptoProvider, sizeof(Ret),
|
||||
reinterpret_cast<BYTE *>(&Ret)))
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// If that fails, fall back to pseudo-random numbers.
|
||||
return GetPseudoRandomNumber();
|
||||
}
|
||||
|
||||
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
||||
|
Loading…
Reference in New Issue
Block a user