xref: /aosp_15_r20/external/cronet/base/rand_util_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #include "third_party/boringssl/src/include/openssl/crypto.h"
19 #include "third_party/boringssl/src/include/openssl/rand.h"
20 
21 // Prototype for ProcessPrng.
22 // See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng
23 extern "C" {
24 BOOL WINAPI ProcessPrng(PBYTE pbData, SIZE_T cbData);
25 }
26 
27 namespace base {
28 
29 namespace internal {
30 
31 namespace {
32 
33 // The BoringSSl helpers are duplicated in rand_util_fuchsia.cc and
34 // rand_util_posix.cc.
35 std::atomic<bool> g_use_boringssl;
36 
37 BASE_FEATURE(kUseBoringSSLForRandBytes,
38              "UseBoringSSLForRandBytes",
39              FEATURE_DISABLED_BY_DEFAULT);
40 
41 }  // namespace
42 
ConfigureBoringSSLBackedRandBytesFieldTrial()43 void ConfigureBoringSSLBackedRandBytesFieldTrial() {
44   g_use_boringssl.store(FeatureList::IsEnabled(kUseBoringSSLForRandBytes),
45                         std::memory_order_relaxed);
46 }
47 
UseBoringSSLForRandBytes()48 bool UseBoringSSLForRandBytes() {
49   return g_use_boringssl.load(std::memory_order_relaxed);
50 }
51 
52 }  // namespace internal
53 
54 namespace {
55 
56 // Import bcryptprimitives!ProcessPrng rather than cryptbase!RtlGenRandom to
57 // avoid opening a handle to \\Device\KsecDD in the renderer.
GetProcessPrng()58 decltype(&ProcessPrng) GetProcessPrng() {
59   HMODULE hmod = LoadLibraryW(L"bcryptprimitives.dll");
60   CHECK(hmod);
61   decltype(&ProcessPrng) process_prng_fn =
62       reinterpret_cast<decltype(&ProcessPrng)>(
63           GetProcAddress(hmod, "ProcessPrng"));
64   CHECK(process_prng_fn);
65   return process_prng_fn;
66 }
67 
RandBytes(span<uint8_t> output,bool avoid_allocation)68 void RandBytes(span<uint8_t> output, bool avoid_allocation) {
69   if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) {
70     // Ensure BoringSSL is initialized so it can use things like RDRAND.
71     CRYPTO_library_init();
72     // BoringSSL's RAND_bytes always returns 1. Any error aborts the program.
73     (void)RAND_bytes(output.data(), output.size());
74     return;
75   }
76 
77   static decltype(&ProcessPrng) process_prng_fn = GetProcessPrng();
78   BOOL success =
79       process_prng_fn(static_cast<BYTE*>(output.data()), output.size());
80   // ProcessPrng is documented to always return TRUE.
81   CHECK(success);
82 }
83 
84 }  // namespace
85 
RandBytes(span<uint8_t> output)86 void RandBytes(span<uint8_t> output) {
87   RandBytes(output, /*avoid_allocation=*/false);
88 }
89 
RandBytes(void * output,size_t output_length)90 void RandBytes(void* output, size_t output_length) {
91   RandBytes(make_span(static_cast<uint8_t*>(output), output_length),
92             /*avoid_allocation=*/false);
93 }
94 
95 namespace internal {
96 
RandDoubleAvoidAllocation()97 double RandDoubleAvoidAllocation() {
98   uint64_t number;
99   RandBytes(as_writable_bytes(make_span(&number, 1u)),
100             /*avoid_allocation=*/true);
101   // This transformation is explained in rand_util.cc.
102   return (number >> 11) * 0x1.0p-53;
103 }
104 
105 }  // namespace internal
106 
107 }  // namespace base
108