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