diff --git a/src/crypto/rand/windows.cc b/src/crypto/rand/windows.cc index 59df467e7..aa5ac076c 100644 --- a/src/crypto/rand/windows.cc +++ b/src/crypto/rand/windows.cc @@ -24,6 +24,7 @@ #include #include +#include #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -57,16 +58,40 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) { // See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng typedef BOOL (WINAPI *ProcessPrngFunction)(PBYTE pbData, SIZE_T cbData); static ProcessPrngFunction g_processprng_fn = NULL; +static HCRYPTPROV g_hCryptProv = 0; + +static BOOL WINAPI wrapper_CryptGenRandom(PBYTE pbData, SIZE_T cbData) +{ + return CryptGenRandom(g_hCryptProv, cbData, pbData); +} static void init_processprng(void) { HMODULE hmod = LoadLibraryW(L"bcryptprimitives"); - if (hmod == NULL) { - abort(); - } - g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng"); - if (g_processprng_fn == NULL) { - abort(); + + if (hmod) { + g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng"); + if (g_processprng_fn) { + return; + } + } + + if (CryptAcquireContext(&g_hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) { + g_processprng_fn = &wrapper_CryptGenRandom; + return; } + + DWORD err = GetLastError(); + if (err == NTE_BAD_KEYSET) { + if (CryptAcquireContext(&g_hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + g_processprng_fn = &wrapper_CryptGenRandom; + return; + } + else { + err = GetLastError(); + } + } + + abort(); } void CRYPTO_init_sysrand(void) {