diff --git a/std/random.d b/std/random.d index c2210248edf..2c04feb49ee 100644 --- a/std/random.d +++ b/std/random.d @@ -1772,6 +1772,49 @@ else } } +version (Windows) +{ + pragma(lib, "advapi32.lib"); // `std.registry` does so, too. + + private bool wincryptGenRandom(T)(out T result) @trusted + { + import core.sys.windows.windef : DWORD, PBYTE; + import core.sys.windows.wincrypt : + CryptAcquireContext, + CryptGenRandom, + CryptReleaseContext, + CRYPT_VERIFYCONTEXT, + HCRYPTPROV, + MS_STRONG_PROV, + PROV_RSA_FULL; + + HCRYPTPROV wincryptHandle; + + const gotHandle = CryptAcquireContext( + &wincryptHandle, + null, + MS_STRONG_PROV.ptr, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT, + ); + if (!gotHandle) + return false; + + scope (exit) + if (!CryptReleaseContext(wincryptHandle, 0)) { /* ignore */ } + + const gotRandom = CryptGenRandom( + wincryptHandle, + DWORD(T.sizeof), + cast(PBYTE) &result, + ); + if (!gotRandom) + return false; + + return true; + } +} + /** A "good" seed for initializing random number engines. Initializing with $(D_PARAM unpredictableSeed) makes engines generate different @@ -1788,7 +1831,19 @@ how excellent the source of entropy is. */ @property uint unpredictableSeed() @trusted nothrow @nogc { - version (AnyARC4Random) + version (Windows) + { + uint result; + if (!wincryptGenRandom!uint(result)) + { + version (none) + return fallbackSeed(); + else + assert(false, "CryptAcquireContext() or CryptGenRandom() failed."); + } + return result; + } + else version (AnyARC4Random) { return arc4random(); } @@ -1837,7 +1892,19 @@ if (isUnsigned!UIntType) /// ditto @property UIntType unpredictableSeed() @nogc nothrow @trusted { - version (AnyARC4Random) + version (Windows) + { + UIntType result; + if (!wincryptGenRandom!UIntType(result)) + { + version (none) + return fallbackSeed(); + else + assert(false, "CryptAcquireContext() or CryptGenRandom() failed."); + } + return result; + } + else version (AnyARC4Random) { static if (UIntType.sizeof <= uint.sizeof) {