abseil-cpp/absl/random/internal/seed_material.cc
Go to the documentation of this file.
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/random/internal/seed_material.h"
16 
17 #include <fcntl.h>
18 
19 #ifndef _WIN32
20 #include <unistd.h>
21 #else
22 #include <io.h>
23 #endif
24 
25 #include <algorithm>
26 #include <cerrno>
27 #include <cstdint>
28 #include <cstdlib>
29 #include <cstring>
30 
31 #include "absl/base/dynamic_annotations.h"
32 #include "absl/base/internal/raw_logging.h"
33 #include "absl/strings/ascii.h"
34 #include "absl/strings/escaping.h"
35 #include "absl/strings/string_view.h"
36 #include "absl/strings/strip.h"
37 
38 #if defined(__native_client__)
39 
40 #include <nacl/nacl_random.h>
41 #define ABSL_RANDOM_USE_NACL_SECURE_RANDOM 1
42 
43 #elif defined(_WIN32)
44 
45 #include <windows.h>
46 #define ABSL_RANDOM_USE_BCRYPT 1
47 #pragma comment(lib, "bcrypt.lib")
48 
49 #elif defined(__Fuchsia__)
50 #include <zircon/syscalls.h>
51 
52 #endif
53 
54 #if defined(__GLIBC__) && \
55  (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
56 // glibc >= 2.25 has getentropy()
57 #define ABSL_RANDOM_USE_GET_ENTROPY 1
58 #endif
59 
60 #if defined(__EMSCRIPTEN__)
61 #include <sys/random.h>
62 // Emscripten has getentropy, but it resides in a different header.
63 #define ABSL_RANDOM_USE_GET_ENTROPY 1
64 #endif
65 
66 #if defined(ABSL_RANDOM_USE_BCRYPT)
67 #include <bcrypt.h>
68 
69 #ifndef BCRYPT_SUCCESS
70 #define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
71 #endif
72 // Also link bcrypt; this can be done via linker options or:
73 // #pragma comment(lib, "bcrypt.lib")
74 #endif
75 
76 namespace absl {
78 namespace random_internal {
79 namespace {
80 
81 // Read OS Entropy for random number seeds.
82 // TODO(absl-team): Possibly place a cap on how much entropy may be read at a
83 // time.
84 
85 #if defined(ABSL_RANDOM_USE_BCRYPT)
86 
87 // On Windows potentially use the BCRYPT CNG API to read available entropy.
88 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
89  BCRYPT_ALG_HANDLE hProvider;
90  NTSTATUS ret;
91  ret = BCryptOpenAlgorithmProvider(&hProvider, BCRYPT_RNG_ALGORITHM,
92  MS_PRIMITIVE_PROVIDER, 0);
93  if (!(BCRYPT_SUCCESS(ret))) {
94  ABSL_RAW_LOG(ERROR, "Failed to open crypto provider.");
95  return false;
96  }
97  ret = BCryptGenRandom(
98  hProvider, // provider
99  reinterpret_cast<UCHAR*>(values.data()), // buffer
100  static_cast<ULONG>(sizeof(uint32_t) * values.size()), // bytes
101  0); // flags
102  BCryptCloseAlgorithmProvider(hProvider, 0);
103  return BCRYPT_SUCCESS(ret);
104 }
105 
106 #elif defined(ABSL_RANDOM_USE_NACL_SECURE_RANDOM)
107 
108 // On NaCL use nacl_secure_random to acquire bytes.
109 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
110  auto buffer = reinterpret_cast<uint8_t*>(values.data());
111  size_t buffer_size = sizeof(uint32_t) * values.size();
112 
113  uint8_t* output_ptr = buffer;
114  while (buffer_size > 0) {
115  size_t nread = 0;
116  const int error = nacl_secure_random(output_ptr, buffer_size, &nread);
117  if (error != 0 || nread > buffer_size) {
118  ABSL_RAW_LOG(ERROR, "Failed to read secure_random seed data: %d", error);
119  return false;
120  }
121  output_ptr += nread;
122  buffer_size -= nread;
123  }
124  return true;
125 }
126 
127 #elif defined(__Fuchsia__)
128 
129 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
130  auto buffer = reinterpret_cast<uint8_t*>(values.data());
131  size_t buffer_size = sizeof(uint32_t) * values.size();
132  zx_cprng_draw(buffer, buffer_size);
133  return true;
134 }
135 
136 #else
137 
138 #if defined(ABSL_RANDOM_USE_GET_ENTROPY)
139 // On *nix, use getentropy() if supported. Note that libc may support
140 // getentropy(), but the kernel may not, in which case this function will return
141 // false.
142 bool ReadSeedMaterialFromGetEntropy(absl::Span<uint32_t> values) {
143  auto buffer = reinterpret_cast<uint8_t*>(values.data());
144  size_t buffer_size = sizeof(uint32_t) * values.size();
145  while (buffer_size > 0) {
146  // getentropy() has a maximum permitted length of 256.
147  size_t to_read = std::min<size_t>(buffer_size, 256);
148  int result = getentropy(buffer, to_read);
149  if (result < 0) {
150  return false;
151  }
152  // https://github.com/google/sanitizers/issues/1173
153  // MemorySanitizer can't see through getentropy().
155  buffer += to_read;
156  buffer_size -= to_read;
157  }
158  return true;
159 }
160 #endif // defined(ABSL_RANDOM_GETENTROPY)
161 
162 // On *nix, read entropy from /dev/urandom.
163 bool ReadSeedMaterialFromDevURandom(absl::Span<uint32_t> values) {
164  const char kEntropyFile[] = "/dev/urandom";
165 
166  auto buffer = reinterpret_cast<uint8_t*>(values.data());
167  size_t buffer_size = sizeof(uint32_t) * values.size();
168 
169  int dev_urandom = open(kEntropyFile, O_RDONLY);
170  bool success = (-1 != dev_urandom);
171  if (!success) {
172  return false;
173  }
174 
175  while (success && buffer_size > 0) {
176  int bytes_read = read(dev_urandom, buffer, buffer_size);
177  int read_error = errno;
178  success = (bytes_read > 0);
179  if (success) {
180  buffer += bytes_read;
182  } else if (bytes_read == -1 && read_error == EINTR) {
183  success = true; // Need to try again.
184  }
185  }
186  close(dev_urandom);
187  return success;
188 }
189 
190 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
191 #if defined(ABSL_RANDOM_USE_GET_ENTROPY)
192  if (ReadSeedMaterialFromGetEntropy(values)) {
193  return true;
194  }
195 #endif
196  // Libc may support getentropy, but the kernel may not, so we still have
197  // to fallback to ReadSeedMaterialFromDevURandom().
198  return ReadSeedMaterialFromDevURandom(values);
199 }
200 
201 #endif
202 
203 } // namespace
204 
206  assert(values.data() != nullptr);
207  if (values.data() == nullptr) {
208  return false;
209  }
210  if (values.empty()) {
211  return true;
212  }
213  return ReadSeedMaterialFromOSEntropyImpl(values);
214 }
215 
217  absl::Span<uint32_t> seed_material) {
218  // Algorithm is based on code available at
219  // https://gist.github.com/imneme/540829265469e673d045
220  constexpr uint32_t kInitVal = 0x43b0d7e5;
221  constexpr uint32_t kHashMul = 0x931e8875;
222  constexpr uint32_t kMixMulL = 0xca01f9dd;
223  constexpr uint32_t kMixMulR = 0x4973f715;
224  constexpr uint32_t kShiftSize = sizeof(uint32_t) * 8 / 2;
225 
226  uint32_t hash_const = kInitVal;
227  auto hash = [&](uint32_t value) {
228  value ^= hash_const;
229  hash_const *= kHashMul;
230  value *= hash_const;
231  value ^= value >> kShiftSize;
232  return value;
233  };
234 
235  auto mix = [&](uint32_t x, uint32_t y) {
236  uint32_t result = kMixMulL * x - kMixMulR * y;
237  result ^= result >> kShiftSize;
238  return result;
239  };
240 
241  for (const auto& seq_val : sequence) {
242  for (auto& elem : seed_material) {
243  elem = mix(elem, hash(seq_val));
244  }
245  }
246 }
247 
249  // Salt must be common for all generators within the same process so read it
250  // only once and store in static variable.
251  static const auto salt_material = []() -> absl::optional<uint32_t> {
252  uint32_t salt_value = 0;
253 
255  MakeSpan(&salt_value, 1))) {
256  return salt_value;
257  }
258 
259  return absl::nullopt;
260  }();
261 
262  return salt_material;
263 }
264 
265 } // namespace random_internal
267 } // namespace absl
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
ABSL_ANNOTATE_MEMORY_IS_INITIALIZED
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size)
Definition: third_party/abseil-cpp/absl/base/dynamic_annotations.h:264
absl::Span
Definition: abseil-cpp/absl/types/span.h:152
y
const double y
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3611
elem
Timer elem
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:109
error
grpc_error_handle error
Definition: retry_filter.cc:499
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
hash
uint64_t hash
Definition: ring_hash.cc:284
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::random_internal::ReadSeedMaterialFromOSEntropy
bool ReadSeedMaterialFromOSEntropy(absl::Span< uint32_t > values)
Definition: abseil-cpp/absl/random/internal/seed_material.cc:205
bytes_read
static size_t bytes_read
Definition: test-ipc-heavy-traffic-deadlock-bug.c:47
absl::optional< uint32_t >
close
#define close
Definition: test-fs.c:48
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
buffer
char buffer[1024]
Definition: libuv/docs/code/idle-compute/main.c:8
google::protobuf::ERROR
static const LogLevel ERROR
Definition: bloaty/third_party/protobuf/src/google/protobuf/testing/googletest.h:70
value
const char * value
Definition: hpack_parser_table.cc:165
read
int read(izstream &zs, T *x, Items items)
Definition: bloaty/third_party/zlib/contrib/iostream2/zstream.h:115
absl::random_internal::MixIntoSeedMaterial
void MixIntoSeedMaterial(absl::Span< const uint32_t > sequence, absl::Span< uint32_t > seed_material)
Definition: abseil-cpp/absl/random/internal/seed_material.cc:216
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
values
std::array< int64_t, Size > values
Definition: abseil-cpp/absl/container/btree_benchmark.cc:608
open
#define open
Definition: test-fs.c:46
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::random_internal::GetSaltMaterial
absl::optional< uint32_t > GetSaltMaterial()
Definition: abseil-cpp/absl/random/internal/seed_material.cc:248
NTSTATUS
LONG NTSTATUS
Definition: win.h:198
ABSL_RAW_LOG
#define ABSL_RAW_LOG(severity,...)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:44
versiongenerate.buffer_size
int buffer_size
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/xcode/Scripts/versiongenerate.py:65
absl::MakeSpan
constexpr Span< T > MakeSpan(T *ptr, size_t size) noexcept
Definition: abseil-cpp/absl/types/span.h:661


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:10