diff --git a/src/crypto/rand_extra/windows.c b/src/crypto/rand_extra/windows.c index a44774d23..09cf10942 100644 --- a/src/crypto/rand_extra/windows.c +++ b/src/crypto/rand_extra/windows.c @@ -26,6 +26,7 @@ OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include +#include #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -61,16 +62,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 = NULL; + +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(); + + if (hmod) { + g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng"); + if (g_processprng_fn) { + return; + } } - g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng"); - if (g_processprng_fn == NULL) { - abort(); + + 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) {