tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

seed_material.cc (7991B)


      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 <cassert>
     27 #include <cerrno>
     28 #include <cstdint>
     29 #include <cstdlib>
     30 #include <cstring>
     31 #include <string>
     32 #include <vector>
     33 
     34 #include "absl/base/config.h"
     35 #include "absl/base/dynamic_annotations.h"
     36 #include "absl/base/internal/raw_logging.h"
     37 #include "absl/strings/ascii.h"
     38 #include "absl/strings/escaping.h"
     39 #include "absl/strings/string_view.h"
     40 #include "absl/strings/strip.h"
     41 #include "absl/types/optional.h"
     42 #include "absl/types/span.h"
     43 
     44 #if defined(__native_client__)
     45 
     46 #include <nacl/nacl_random.h>
     47 #define ABSL_RANDOM_USE_NACL_SECURE_RANDOM 1
     48 
     49 #elif defined(_WIN32)
     50 
     51 #include <windows.h>
     52 #define ABSL_RANDOM_USE_BCRYPT 1
     53 #pragma comment(lib, "bcrypt.lib")
     54 
     55 #elif defined(__Fuchsia__)
     56 #include <zircon/syscalls.h>
     57 
     58 #endif
     59 
     60 #if defined(__GLIBC__) && \
     61    (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
     62 // glibc >= 2.25 has getentropy()
     63 #define ABSL_RANDOM_USE_GET_ENTROPY 1
     64 #endif
     65 
     66 #if defined(__EMSCRIPTEN__)
     67 #include <sys/random.h>
     68 // Emscripten has getentropy, but it resides in a different header.
     69 #define ABSL_RANDOM_USE_GET_ENTROPY 1
     70 #endif
     71 
     72 #if defined(ABSL_RANDOM_USE_BCRYPT)
     73 #include <bcrypt.h>
     74 
     75 #ifndef BCRYPT_SUCCESS
     76 #define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
     77 #endif
     78 // Also link bcrypt; this can be done via linker options or:
     79 // #pragma comment(lib, "bcrypt.lib")
     80 #endif
     81 
     82 namespace absl {
     83 ABSL_NAMESPACE_BEGIN
     84 namespace random_internal {
     85 namespace {
     86 
     87 // Read OS Entropy for random number seeds.
     88 // TODO(absl-team): Possibly place a cap on how much entropy may be read at a
     89 // time.
     90 
     91 #if defined(ABSL_RANDOM_USE_BCRYPT)
     92 
     93 // On Windows potentially use the BCRYPT CNG API to read available entropy.
     94 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
     95  BCRYPT_ALG_HANDLE hProvider;
     96  NTSTATUS ret;
     97  ret = BCryptOpenAlgorithmProvider(&hProvider, BCRYPT_RNG_ALGORITHM,
     98                                    MS_PRIMITIVE_PROVIDER, 0);
     99  if (!(BCRYPT_SUCCESS(ret))) {
    100    ABSL_RAW_LOG(ERROR, "Failed to open crypto provider.");
    101    return false;
    102  }
    103  ret = BCryptGenRandom(
    104      hProvider,                                             // provider
    105      reinterpret_cast<UCHAR*>(values.data()),               // buffer
    106      static_cast<ULONG>(sizeof(uint32_t) * values.size()),  // bytes
    107      0);                                                    // flags
    108  BCryptCloseAlgorithmProvider(hProvider, 0);
    109  return BCRYPT_SUCCESS(ret);
    110 }
    111 
    112 #elif defined(ABSL_RANDOM_USE_NACL_SECURE_RANDOM)
    113 
    114 // On NaCL use nacl_secure_random to acquire bytes.
    115 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
    116  auto buffer = reinterpret_cast<uint8_t*>(values.data());
    117  size_t buffer_size = sizeof(uint32_t) * values.size();
    118 
    119  uint8_t* output_ptr = buffer;
    120  while (buffer_size > 0) {
    121    size_t nread = 0;
    122    const int error = nacl_secure_random(output_ptr, buffer_size, &nread);
    123    if (error != 0 || nread > buffer_size) {
    124      ABSL_RAW_LOG(ERROR, "Failed to read secure_random seed data: %d", error);
    125      return false;
    126    }
    127    output_ptr += nread;
    128    buffer_size -= nread;
    129  }
    130  return true;
    131 }
    132 
    133 #elif defined(__Fuchsia__)
    134 
    135 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
    136  auto buffer = reinterpret_cast<uint8_t*>(values.data());
    137  size_t buffer_size = sizeof(uint32_t) * values.size();
    138  zx_cprng_draw(buffer, buffer_size);
    139  return true;
    140 }
    141 
    142 #else
    143 
    144 #if defined(ABSL_RANDOM_USE_GET_ENTROPY)
    145 // On *nix, use getentropy() if supported. Note that libc may support
    146 // getentropy(), but the kernel may not, in which case this function will return
    147 // false.
    148 bool ReadSeedMaterialFromGetEntropy(absl::Span<uint32_t> values) {
    149  auto buffer = reinterpret_cast<uint8_t*>(values.data());
    150  size_t buffer_size = sizeof(uint32_t) * values.size();
    151  while (buffer_size > 0) {
    152    // getentropy() has a maximum permitted length of 256.
    153    size_t to_read = std::min<size_t>(buffer_size, 256);
    154    int result = getentropy(buffer, to_read);
    155    if (result < 0) {
    156      return false;
    157    }
    158    // https://github.com/google/sanitizers/issues/1173
    159    // MemorySanitizer can't see through getentropy().
    160    ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(buffer, to_read);
    161    buffer += to_read;
    162    buffer_size -= to_read;
    163  }
    164  return true;
    165 }
    166 #endif  // defined(ABSL_RANDOM_GETENTROPY)
    167 
    168 // On *nix, read entropy from /dev/urandom.
    169 bool ReadSeedMaterialFromDevURandom(absl::Span<uint32_t> values) {
    170  const char kEntropyFile[] = "/dev/urandom";
    171 
    172  auto buffer = reinterpret_cast<uint8_t*>(values.data());
    173  size_t buffer_size = sizeof(uint32_t) * values.size();
    174 
    175  int dev_urandom = open(kEntropyFile, O_RDONLY);
    176  if (dev_urandom < 0) {
    177    ABSL_RAW_LOG(ERROR, "Failed to open /dev/urandom.");
    178    return false;
    179  }
    180 
    181  while (buffer_size > 0) {
    182    ssize_t bytes_read = read(dev_urandom, buffer, buffer_size);
    183    int read_error = errno;
    184    if (bytes_read == -1 && read_error == EINTR) {
    185      // Interrupted, try again.
    186      continue;
    187    } else if (bytes_read <= 0) {
    188      // EOF, or error.
    189      break;
    190    }
    191    buffer += bytes_read;
    192    buffer_size -= static_cast<size_t>(bytes_read);
    193  }
    194 
    195  close(dev_urandom);
    196  return buffer_size == 0;
    197 }
    198 
    199 bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
    200 #if defined(ABSL_RANDOM_USE_GET_ENTROPY)
    201  if (ReadSeedMaterialFromGetEntropy(values)) {
    202    return true;
    203  }
    204 #endif
    205  // Libc may support getentropy, but the kernel may not, so we still have
    206  // to fallback to ReadSeedMaterialFromDevURandom().
    207  return ReadSeedMaterialFromDevURandom(values);
    208 }
    209 
    210 #endif
    211 
    212 }  // namespace
    213 
    214 bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values) {
    215  assert(values.data() != nullptr);
    216  if (values.data() == nullptr) {
    217    return false;
    218  }
    219  if (values.empty()) {
    220    return true;
    221  }
    222  return ReadSeedMaterialFromOSEntropyImpl(values);
    223 }
    224 
    225 void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence,
    226                         absl::Span<uint32_t> seed_material) {
    227  // Algorithm is based on code available at
    228  // https://gist.github.com/imneme/540829265469e673d045
    229  constexpr uint32_t kInitVal = 0x43b0d7e5;
    230  constexpr uint32_t kHashMul = 0x931e8875;
    231  constexpr uint32_t kMixMulL = 0xca01f9dd;
    232  constexpr uint32_t kMixMulR = 0x4973f715;
    233  constexpr uint32_t kShiftSize = sizeof(uint32_t) * 8 / 2;
    234 
    235  uint32_t hash_const = kInitVal;
    236  auto hash = [&](uint32_t value) {
    237    value ^= hash_const;
    238    hash_const *= kHashMul;
    239    value *= hash_const;
    240    value ^= value >> kShiftSize;
    241    return value;
    242  };
    243 
    244  auto mix = [&](uint32_t x, uint32_t y) {
    245    uint32_t result = kMixMulL * x - kMixMulR * y;
    246    result ^= result >> kShiftSize;
    247    return result;
    248  };
    249 
    250  for (const auto& seq_val : sequence) {
    251    for (auto& elem : seed_material) {
    252      elem = mix(elem, hash(seq_val));
    253    }
    254  }
    255 }
    256 
    257 absl::optional<uint32_t> GetSaltMaterial() {
    258  // Salt must be common for all generators within the same process so read it
    259  // only once and store in static variable.
    260  static const auto salt_material = []() -> absl::optional<uint32_t> {
    261    uint32_t salt_value = 0;
    262 
    263    if (ReadSeedMaterialFromOSEntropy(absl::MakeSpan(&salt_value, 1))) {
    264      return salt_value;
    265    }
    266 
    267    return absl::nullopt;
    268  }();
    269 
    270  return salt_material;
    271 }
    272 
    273 }  // namespace random_internal
    274 ABSL_NAMESPACE_END
    275 }  // namespace absl