9#include <botan/system_rng.h>
11#include <botan/assert.h>
12#include <botan/internal/target_info.h>
14#if defined(BOTAN_TARGET_OS_HAS_WIN32)
20#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
21 #include <botan/internal/dyn_load.h>
22#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
25#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
26 #include <CommonCrypto/CommonRandom.h>
27#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
29#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
31 #include <sys/random.h>
32 #include <sys/syscall.h>
34#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
44#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
48 System_RNG_Impl() : m_advapi(
"advapi32.dll") {
50 m_rtlgenrandom = m_advapi.resolve<RtlGenRandom_fptr>(
"SystemFunction036");
53 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
54 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
55 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
56 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
58 bool is_seeded()
const override {
return true; }
60 bool accepts_input()
const override {
return false; }
62 void clear()
override {
65 std::string name()
const override {
return "RtlGenRandom"; }
68 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
69 const size_t limit = std::numeric_limits<ULONG>::max();
71 uint8_t* pData = output.data();
72 size_t bytesLeft = output.size();
73 while(bytesLeft > 0) {
74 const ULONG blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
76 const bool success = m_rtlgenrandom(pData, blockSize) ==
TRUE;
78 throw System_Error(
"RtlGenRandom failed");
81 BOTAN_ASSERT(bytesLeft >= blockSize,
"Block is oversized");
82 bytesLeft -= blockSize;
88 using RtlGenRandom_fptr = BOOLEAN(NTAPI*)(PVOID, ULONG);
90 Dynamically_Loaded_Library m_advapi;
91 RtlGenRandom_fptr m_rtlgenrandom;
94#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
99 auto ret = ::BCryptOpenAlgorithmProvider(&m_prov, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
100 if(!BCRYPT_SUCCESS(ret)) {
101 throw System_Error(
"System_RNG failed to acquire crypto provider", ret);
105 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
106 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
107 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
108 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
110 ~System_RNG_Impl()
override { ::BCryptCloseAlgorithmProvider(m_prov, 0); }
112 bool is_seeded()
const override {
return true; }
114 bool accepts_input()
const override {
return false; }
116 void clear()
override {
119 std::string name()
const override {
return "crypto_ng"; }
122 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
128 const size_t limit = std::numeric_limits<ULONG>::max();
130 uint8_t* pData = output.data();
131 size_t bytesLeft = output.size();
132 while(bytesLeft > 0) {
133 const ULONG blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
135 auto ret = BCryptGenRandom(m_prov,
static_cast<PUCHAR
>(pData), blockSize, 0);
136 if(!BCRYPT_SUCCESS(ret)) {
137 throw System_Error(
"System_RNG call to BCryptGenRandom failed", ret);
140 BOTAN_ASSERT(bytesLeft >= blockSize,
"Block is oversized");
141 bytesLeft -= blockSize;
147 BCRYPT_ALG_HANDLE m_prov;
150#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
154 bool accepts_input()
const override {
return false; }
156 bool is_seeded()
const override {
return true; }
158 void clear()
override {
161 std::string name()
const override {
return "CCRandomGenerateBytes"; }
164 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
165 if(::CCRandomGenerateBytes(output.data(), output.size()) != kCCSuccess) {
166 throw System_Error(
"System_RNG CCRandomGenerateBytes failed", errno);
171#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
177 bool accepts_input()
const override {
return false; }
179 bool is_seeded()
const override {
return true; }
181 void clear()
override {
184 std::string name()
const override {
return "arc4random"; }
187 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
191 if(!output.empty()) {
192 ::arc4random_buf(output.data(), output.size());
197#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
203 bool accepts_input()
const override {
return false; }
205 bool is_seeded()
const override {
return true; }
207 void clear()
override {
210 std::string name()
const override {
return "getrandom"; }
213 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
214 const unsigned int flags = 0;
216 uint8_t* buf = output.data();
217 size_t len = output.size();
219 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 25
220 const ssize_t got = ::syscall(SYS_getrandom, buf, len, flags);
222 const ssize_t got = ::getrandom(buf, len, flags);
229 throw System_Error(
"System_RNG getrandom failed", errno);
238#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
253 m_fd = ::open(
"/dev/random", O_RDONLY | O_NOCTTY);
255 throw System_Error(
"System_RNG failed to open RNG device", errno);
258 const size_t got = ::read(m_fd, &b, 1);
262 throw System_Error(
"System_RNG failed to read blocking RNG device");
264 m_fd = ::open(
"/dev/urandom", O_RDWR | O_NOCTTY);
273 m_fd = ::open(
"/dev/urandom", O_RDONLY | O_NOCTTY);
278 throw System_Error(
"System_RNG failed to open RNG device", errno);
281 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
282 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
283 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
284 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
286 ~System_RNG_Impl()
override {
291 bool is_seeded()
const override {
return true; }
293 bool accepts_input()
const override {
return m_writable; }
295 void clear()
override {
298 std::string name()
const override {
return "urandom"; }
301 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override;
302 void maybe_write_entropy(std::span<const uint8_t> input);
309void System_RNG_Impl::fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
310 maybe_write_entropy(input);
312 uint8_t* buf = output.data();
313 size_t len = output.size();
315 ssize_t got = ::read(m_fd, buf, len);
330void System_RNG_Impl::maybe_write_entropy(std::span<const uint8_t> entropy_input) {
331 if(!m_writable || entropy_input.empty())
334 const uint8_t* input = entropy_input.data();
335 size_t len = entropy_input.size();
337 ssize_t got = ::write(m_fd, input, len);
355 if(errno == EPERM || errno == EBADF)
372 static System_RNG_Impl g_system_rng;
#define BOTAN_ASSERT(expr, assertion_made)
RandomNumberGenerator & system_rng()