From a3b6342f23dae312c6713c10e06c002b0585b1e7 Mon Sep 17 00:00:00 2001 From: Elias Batek Date: Sun, 19 Jan 2025 04:37:46 +0100 Subject: [PATCH] Make `unpredictableSeed` use `CryptGenRandom` (CryptoAPI) on Windows --- std/random.d | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/std/random.d b/std/random.d index c2210248edf..b71a0d0c8d7 100644 --- a/std/random.d +++ b/std/random.d @@ -1772,6 +1772,41 @@ 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; + import core.sys.windows.wincrypt; + + HCRYPTPROV wincryptHandle; + + const gotHandle = CryptAcquireContext( + &wincryptHandle, + MS_STRONG_PROV, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT, + ); + if (!gotHandle) + return false; + + scope (exit) + if (!CryptReleaseContext(&wincryptHandle, 0)) { /* ignore */ } + + const gotRandom = CryptGenRandom( + wincryptHandle, + DWORD(T.sizeof), + cast(void*) &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 +1823,19 @@ how excellent the source of entropy is. */ @property uint unpredictableSeed() @trusted nothrow @nogc { - version (AnyARC4Random) + version (Windows) + { + uint result; + if (!wincryptGenRandom!UIntType(result)) + { + version (none) + return fallbackSeed(); + else + assert(false, "CryptAcquireContext() or CryptGenRandom() failed."); + } + return result; + } + else version (AnyARC4Random) { return arc4random(); } @@ -1837,7 +1884,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) {