/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/Random.h>
+#include <array>
#include <atomic>
-#include <unistd.h>
-#include <sys/time.h>
+#include <mutex>
#include <random>
-#include <array>
-#include <glog/logging.h>
#include <folly/File.h>
#include <folly/FileUtil.h>
+#include <folly/SingletonThreadLocal.h>
+#include <folly/ThreadLocal.h>
+#include <folly/portability/SysTime.h>
+#include <folly/portability/Unistd.h>
+#include <folly/synchronization/CallOnce.h>
+#include <glog/logging.h>
+
+#ifdef _MSC_VER
+#include <wincrypt.h> // @manual
+#endif
namespace folly {
namespace {
void readRandomDevice(void* data, size_t size) {
- // Keep it open for the duration of the program
- static File randomDevice("/dev/urandom");
- PCHECK(readFull(randomDevice.fd(), data, size) == size);
+#ifdef _MSC_VER
+ static folly::once_flag flag;
+ static HCRYPTPROV cryptoProv;
+ folly::call_once(flag, [&] {
+ if (!CryptAcquireContext(
+ &cryptoProv,
+ nullptr,
+ nullptr,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ if (GetLastError() == NTE_BAD_KEYSET) {
+ // Mostly likely cause of this is that no key container
+ // exists yet, so try to create one.
+ PCHECK(CryptAcquireContext(
+ &cryptoProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET));
+ } else {
+ LOG(FATAL) << "Failed to acquire the default crypto context.";
+ }
+ }
+ });
+ CHECK(size <= std::numeric_limits<DWORD>::max());
+ PCHECK(CryptGenRandom(cryptoProv, (DWORD)size, (BYTE*)data));
+#else
+ // Keep the random device open for the duration of the program.
+ static int randomFd = ::open("/dev/urandom", O_RDONLY);
+ PCHECK(randomFd >= 0);
+ auto bytesRead = readFull(randomFd, data, size);
+ PCHECK(bytesRead >= 0 && size_t(bytesRead) == size);
+#endif
}
class BufferedRandomDevice {
void getSlow(unsigned char* data, size_t size);
inline size_t remaining() const {
- return buffer_.get() + bufferSize_ - ptr_;
+ return size_t(buffer_.get() + bufferSize_ - ptr_);
}
const size_t bufferSize_;
ptr_ += size;
}
-ThreadLocal<BufferedRandomDevice> bufferedRandomDevice;
+struct RandomTag {};
-} // namespace
+} // namespace
void Random::secureRandom(void* data, size_t size) {
- bufferedRandomDevice->get(data, size);
+ static SingletonThreadLocal<BufferedRandomDevice, RandomTag>
+ bufferedRandomDevice;
+ bufferedRandomDevice.get().get(data, size);
}
-folly::ThreadLocalPtr<ThreadLocalPRNG::LocalInstancePRNG>
-ThreadLocalPRNG::localInstance;
-
class ThreadLocalPRNG::LocalInstancePRNG {
public:
- LocalInstancePRNG() : rng(Random::create()) { }
+ LocalInstancePRNG() : rng(Random::create()) {}
Random::DefaultGenerator rng;
};
-ThreadLocalPRNG::LocalInstancePRNG* ThreadLocalPRNG::initLocal() {
- auto ret = new LocalInstancePRNG;
- localInstance.reset(ret);
- return ret;
+ThreadLocalPRNG::ThreadLocalPRNG() {
+ static SingletonThreadLocal<ThreadLocalPRNG::LocalInstancePRNG, RandomTag>
+ localInstancePRNG;
+ local_ = &localInstancePRNG.get();
}
uint32_t ThreadLocalPRNG::getImpl(LocalInstancePRNG* local) {
return local->rng();
}
-
-}
+} // namespace folly