Random.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright 2011-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/Random.h>
  17. #include <array>
  18. #include <atomic>
  19. #include <mutex>
  20. #include <random>
  21. #include <folly/File.h>
  22. #include <folly/FileUtil.h>
  23. #include <folly/SingletonThreadLocal.h>
  24. #include <folly/ThreadLocal.h>
  25. #include <folly/portability/SysTime.h>
  26. #include <folly/portability/Unistd.h>
  27. #include <folly/synchronization/CallOnce.h>
  28. #include <glog/logging.h>
  29. #ifdef _MSC_VER
  30. #include <wincrypt.h> // @manual
  31. #endif
  32. namespace folly {
  33. namespace {
  34. void readRandomDevice(void* data, size_t size) {
  35. #ifdef _MSC_VER
  36. static folly::once_flag flag;
  37. static HCRYPTPROV cryptoProv;
  38. folly::call_once(flag, [&] {
  39. if (!CryptAcquireContext(
  40. &cryptoProv,
  41. nullptr,
  42. nullptr,
  43. PROV_RSA_FULL,
  44. CRYPT_VERIFYCONTEXT)) {
  45. if (GetLastError() == NTE_BAD_KEYSET) {
  46. // Mostly likely cause of this is that no key container
  47. // exists yet, so try to create one.
  48. PCHECK(CryptAcquireContext(
  49. &cryptoProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET));
  50. } else {
  51. LOG(FATAL) << "Failed to acquire the default crypto context.";
  52. }
  53. }
  54. });
  55. CHECK(size <= std::numeric_limits<DWORD>::max());
  56. PCHECK(CryptGenRandom(cryptoProv, (DWORD)size, (BYTE*)data));
  57. #else
  58. // Keep the random device open for the duration of the program.
  59. static int randomFd = ::open("/dev/urandom", O_RDONLY | O_CLOEXEC);
  60. PCHECK(randomFd >= 0);
  61. auto bytesRead = readFull(randomFd, data, size);
  62. PCHECK(bytesRead >= 0 && size_t(bytesRead) == size);
  63. #endif
  64. }
  65. class BufferedRandomDevice {
  66. public:
  67. static once_flag flag;
  68. static constexpr size_t kDefaultBufferSize = 128;
  69. static void notifyNewGlobalEpoch() {
  70. globalEpoch_.fetch_add(1, std::memory_order_relaxed);
  71. }
  72. explicit BufferedRandomDevice(size_t bufferSize = kDefaultBufferSize);
  73. void get(void* data, size_t size) {
  74. auto const globalEpoch = globalEpoch_.load(std::memory_order_relaxed);
  75. if (LIKELY(globalEpoch == epoch_ && size <= remaining())) {
  76. memcpy(data, ptr_, size);
  77. ptr_ += size;
  78. } else {
  79. getSlow(static_cast<unsigned char*>(data), size);
  80. }
  81. }
  82. private:
  83. void getSlow(unsigned char* data, size_t size);
  84. inline size_t remaining() const {
  85. return size_t(buffer_.get() + bufferSize_ - ptr_);
  86. }
  87. static std::atomic<size_t> globalEpoch_;
  88. size_t epoch_{size_t(-1)}; // refill on first use
  89. const size_t bufferSize_;
  90. std::unique_ptr<unsigned char[]> buffer_;
  91. unsigned char* ptr_;
  92. };
  93. once_flag BufferedRandomDevice::flag;
  94. std::atomic<size_t> BufferedRandomDevice::globalEpoch_{0};
  95. struct RandomTag {};
  96. BufferedRandomDevice::BufferedRandomDevice(size_t bufferSize)
  97. : bufferSize_(bufferSize),
  98. buffer_(new unsigned char[bufferSize]),
  99. ptr_(buffer_.get() + bufferSize) { // refill on first use
  100. call_once(flag, [this]() {
  101. detail::AtFork::registerHandler(
  102. this,
  103. /*prepare*/ []() { return true; },
  104. /*parent*/ []() {},
  105. /*child*/
  106. []() {
  107. // Ensure child and parent do not share same entropy pool.
  108. BufferedRandomDevice::notifyNewGlobalEpoch();
  109. });
  110. });
  111. }
  112. void BufferedRandomDevice::getSlow(unsigned char* data, size_t size) {
  113. auto const globalEpoch = globalEpoch_.load(std::memory_order_relaxed);
  114. if (globalEpoch != epoch_) {
  115. epoch_ = globalEpoch_;
  116. ptr_ = buffer_.get() + bufferSize_;
  117. }
  118. DCHECK_GT(size, remaining());
  119. if (size >= bufferSize_) {
  120. // Just read directly.
  121. readRandomDevice(data, size);
  122. return;
  123. }
  124. size_t copied = remaining();
  125. memcpy(data, ptr_, copied);
  126. data += copied;
  127. size -= copied;
  128. // refill
  129. readRandomDevice(buffer_.get(), bufferSize_);
  130. ptr_ = buffer_.get();
  131. memcpy(data, ptr_, size);
  132. ptr_ += size;
  133. }
  134. } // namespace
  135. void Random::secureRandom(void* data, size_t size) {
  136. using Single = SingletonThreadLocal<BufferedRandomDevice, RandomTag>;
  137. Single::get().get(data, size);
  138. }
  139. ThreadLocalPRNG::result_type ThreadLocalPRNG::operator()() {
  140. struct Wrapper {
  141. Random::DefaultGenerator object{Random::create()};
  142. };
  143. using Single = SingletonThreadLocal<Wrapper, RandomTag>;
  144. return Single::get().object();
  145. }
  146. } // namespace folly