rand_util_win.cc (2879B)
1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/rand_util.h" 6 7 #include <windows.h> 8 9 #include <stddef.h> 10 #include <stdint.h> 11 12 #include <algorithm> 13 #include <atomic> 14 #include <limits> 15 16 #include "base/check.h" 17 #include "base/feature_list.h" 18 #if !defined(MOZ_SANDBOX) 19 #include "third_party/boringssl/src/include/openssl/crypto.h" 20 #include "third_party/boringssl/src/include/openssl/rand.h" 21 #endif 22 23 // Prototype for ProcessPrng. 24 // See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng 25 extern "C" { 26 BOOL WINAPI ProcessPrng(PBYTE pbData, SIZE_T cbData); 27 } 28 29 namespace base { 30 31 #if !defined(MOZ_SANDBOX) 32 namespace internal { 33 34 namespace { 35 36 // The BoringSSl helpers are duplicated in rand_util_fuchsia.cc and 37 // rand_util_posix.cc. 38 std::atomic<bool> g_use_boringssl; 39 40 BASE_FEATURE(kUseBoringSSLForRandBytes, 41 "UseBoringSSLForRandBytes", 42 FEATURE_DISABLED_BY_DEFAULT); 43 44 } // namespace 45 46 void ConfigureBoringSSLBackedRandBytesFieldTrial() { 47 g_use_boringssl.store(FeatureList::IsEnabled(kUseBoringSSLForRandBytes), 48 std::memory_order_relaxed); 49 } 50 51 bool UseBoringSSLForRandBytes() { 52 return g_use_boringssl.load(std::memory_order_relaxed); 53 } 54 55 } // namespace internal 56 #endif 57 58 namespace { 59 60 // Import bcryptprimitives!ProcessPrng rather than cryptbase!RtlGenRandom to 61 // avoid opening a handle to \\Device\KsecDD in the renderer. 62 decltype(&ProcessPrng) GetProcessPrng() { 63 HMODULE hmod = LoadLibraryW(L"bcryptprimitives.dll"); 64 CHECK(hmod); 65 decltype(&ProcessPrng) process_prng_fn = 66 reinterpret_cast<decltype(&ProcessPrng)>( 67 GetProcAddress(hmod, "ProcessPrng")); 68 CHECK(process_prng_fn); 69 return process_prng_fn; 70 } 71 72 void RandBytes(void* output, size_t output_length, bool avoid_allocation) { 73 #if !defined(MOZ_SANDBOX) 74 if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) { 75 // Ensure BoringSSL is initialized so it can use things like RDRAND. 76 CRYPTO_library_init(); 77 // BoringSSL's RAND_bytes always returns 1. Any error aborts the program. 78 (void)RAND_bytes(static_cast<uint8_t*>(output), output_length); 79 return; 80 } 81 #endif 82 83 static decltype(&ProcessPrng) process_prng_fn = GetProcessPrng(); 84 BOOL success = process_prng_fn(static_cast<BYTE*>(output), output_length); 85 // ProcessPrng is documented to always return TRUE. 86 CHECK(success); 87 } 88 89 } // namespace 90 91 void RandBytes(void* output, size_t output_length) { 92 RandBytes(output, output_length, /*avoid_allocation=*/false); 93 } 94 95 namespace internal { 96 97 double RandDoubleAvoidAllocation() { 98 uint64_t number; 99 RandBytes(&number, sizeof(number), /*avoid_allocation=*/true); 100 // This transformation is explained in rand_util.cc. 101 return (number >> 11) * 0x1.0p-53; 102 } 103 104 } // namespace internal 105 106 } // namespace base