diff --git a/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c b/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c index 64c4cec5..42d02235 100644 --- a/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c +++ b/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c @@ -58,15 +58,13 @@ #ifdef _WIN32 # include # include -# define RtlGenRandom SystemFunction036 -# if defined(__cplusplus) -extern "C" -# endif -BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); -# pragma comment(lib, "advapi32.lib") +# include +# include + typedef NTSTATUS(FAR PASCAL *CNGAPI_DRBG)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG, + ULONG); # ifdef __BORLANDC__ -# define _ftime ftime -# define _timeb timeb +# define _ftime ftime +# define _timeb timeb # endif #endif @@ -373,11 +371,44 @@ randombytes_salsa20_random_stir(void) # endif #else /* _WIN32 */ - if (! RtlGenRandom((PVOID) stream.key, (ULONG) sizeof stream.key)) { - sodium_misuse(); /* LCOV_EXCL_LINE */ + HANDLE hCAPINg; + BOOL rtld; + CNGAPI_DRBG getrandom; + HCRYPTPROV hProv; + /* load bcrypt dynamically, see if we're already loaded */ + rtld = FALSE; + hCAPINg = GetModuleHandle("bcrypt.dll"); + /* otherwise, load CNG manually */ + if(!hCAPINg) + { + hCAPINg = LoadLibraryEx("bcrypt.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + rtld = TRUE; + } + if(hCAPINg) + { + /* call BCryptGenRandom(2) */ + getrandom = (CNGAPI_DRBG)GetProcAddress(hCAPINg, "BCryptGenRandom"); + if(!BCRYPT_SUCCESS( + getrandom(NULL, stream.key, sizeof stream.key, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) + { + sodium_misuse(); } + /* don't leak lib refs */ + if(rtld) + FreeLibrary(hCAPINg); + } + /* if that fails use the regular ARC4-SHA1 RNG (!!!) *cringes* */ + else + { + CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT); + if(!CryptGenRandom(hProv, sizeof stream.key, stream.key)) + { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + CryptReleaseContext(hProv, 0); + } #endif - stream.initialized = 1; } diff --git a/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c b/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c index 99018f35..e2cacfb9 100644 --- a/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c +++ b/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c @@ -48,28 +48,12 @@ #include "utils.h" #ifdef _WIN32 -/* `RtlGenRandom` is used over `CryptGenRandom` on Microsoft Windows based systems: - * - `CryptGenRandom` requires pulling in `CryptoAPI` which causes unnecessary - * memory overhead if this API is not being used for other purposes - * - `RtlGenRandom` is thus called directly instead. A detailed explanation - * can be found here: https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/ - * - * In spite of the disclaimer on the `RtlGenRandom` documentation page that was - * written back in the Windows XP days, this function is here to stay. The CRT - * function `rand_s()` directly depends on it, so touching it would break many - * applications released since Windows XP. - * - * Also note that Rust, Firefox and BoringSSL (thus, Google Chrome and everything - * based on Chromium) also depend on it, and that libsodium allows the RNG to be - * replaced without patching nor recompiling the library. - */ # include -# define RtlGenRandom SystemFunction036 -# if defined(__cplusplus) -extern "C" -# endif -BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); -# pragma comment(lib, "advapi32.lib") +# include +# include +# include + typedef NTSTATUS(FAR PASCAL *CNGAPI_DRBG)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG, + ULONG); #endif #if defined(__OpenBSD__) || defined(__CloudABI__) @@ -359,9 +343,43 @@ randombytes_sysrandom_buf(void * const buf, const size_t size) if (size > (size_t) 0xffffffffUL) { sodium_misuse(); /* LCOV_EXCL_LINE */ } - if (! RtlGenRandom((PVOID) buf, (ULONG) size)) { - sodium_misuse(); /* LCOV_EXCL_LINE */ + HANDLE hCAPINg; + BOOL rtld; + CNGAPI_DRBG getrandom; + HCRYPTPROV hProv; + /* load bcrypt dynamically, see if we're already loaded */ + rtld = FALSE; + hCAPINg = GetModuleHandle("bcrypt.dll"); + /* otherwise, load CNG manually */ + if(!hCAPINg) + { + hCAPINg = LoadLibraryEx("bcrypt.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + rtld = TRUE; + } + if(hCAPINg) + { + /* call BCryptGenRandom(2) */ + getrandom = (CNGAPI_DRBG)GetProcAddress(hCAPINg, "BCryptGenRandom"); + if(!BCRYPT_SUCCESS( + getrandom(NULL, buf, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) + { + sodium_misuse(); + } + /* don't leak lib refs */ + if(rtld) + FreeLibrary(hCAPINg); + } + /* if that fails use the regular ARC4-SHA1 RNG (!!!) *cringes* */ + else + { + CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT); + if(!CryptGenRandom(hProv, size, buf)) + { + sodium_misuse(); /* LCOV_EXCL_LINE */ } + CryptReleaseContext(hProv, 0); + } # endif /* _WIN32 */ }