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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/rand_util.h"
11
12 #include <windows.h>
13
14 #include <stddef.h>
15 #include <stdint.h>
16
17 #include <algorithm>
18 #include <atomic>
19 #include <limits>
20
21 #include "base/check.h"
22 #include "base/feature_list.h"
23 #include "third_party/boringssl/src/include/openssl/rand.h"
24
25 // Prototype for ProcessPrng.
26 // See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng
27 extern "C" {
28 BOOL WINAPI ProcessPrng(PBYTE pbData, SIZE_T cbData);
29 }
30
31 namespace base {
32
33 namespace internal {
34
35 namespace {
36
37 // The BoringSSl helpers are duplicated in rand_util_fuchsia.cc and
38 // rand_util_posix.cc.
39 std::atomic<bool> g_use_boringssl;
40
41 BASE_FEATURE(kUseBoringSSLForRandBytes,
42 "UseBoringSSLForRandBytes",
43 FEATURE_DISABLED_BY_DEFAULT);
44
45 } // namespace
46
ConfigureBoringSSLBackedRandBytesFieldTrial()47 void ConfigureBoringSSLBackedRandBytesFieldTrial() {
48 g_use_boringssl.store(FeatureList::IsEnabled(kUseBoringSSLForRandBytes),
49 std::memory_order_relaxed);
50 }
51
UseBoringSSLForRandBytes()52 bool UseBoringSSLForRandBytes() {
53 return g_use_boringssl.load(std::memory_order_relaxed);
54 }
55
56 } // namespace internal
57
58 namespace {
59
60 // Import bcryptprimitives!ProcessPrng rather than cryptbase!RtlGenRandom to
61 // avoid opening a handle to \\Device\KsecDD in the renderer.
GetProcessPrng()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
RandBytesInternal(span<uint8_t> output,bool avoid_allocation)72 void RandBytesInternal(span<uint8_t> output, bool avoid_allocation) {
73 if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) {
74 // BoringSSL's RAND_bytes always returns 1. Any error aborts the program.
75 (void)RAND_bytes(output.data(), output.size());
76 return;
77 }
78
79 static decltype(&ProcessPrng) process_prng_fn = GetProcessPrng();
80 BOOL success =
81 process_prng_fn(static_cast<BYTE*>(output.data()), output.size());
82 // ProcessPrng is documented to always return TRUE.
83 CHECK(success);
84 }
85
86 } // namespace
87
RandBytes(span<uint8_t> output)88 void RandBytes(span<uint8_t> output) {
89 RandBytesInternal(output, /*avoid_allocation=*/false);
90 }
91
92 namespace internal {
93
RandDoubleAvoidAllocation()94 double RandDoubleAvoidAllocation() {
95 uint64_t number;
96 RandBytesInternal(byte_span_from_ref(number),
97 /*avoid_allocation=*/true);
98 // This transformation is explained in rand_util.cc.
99 return (number >> 11) * 0x1.0p-53;
100 }
101
102 } // namespace internal
103
104 } // namespace base
105