9#include <botan/system_rng.h>
11#include <botan/assert.h>
12#include <botan/exceptn.h>
13#include <botan/internal/target_info.h>
15#if defined(BOTAN_TARGET_OS_HAS_WIN32)
21#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
22 #include <botan/internal/dyn_load.h>
24#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
27#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
28 #include <CommonCrypto/CommonRandom.h>
29#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
31#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
33 #include <sys/random.h>
34 #include <sys/syscall.h>
36#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
46#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
50 System_RNG_Impl() : m_advapi(
"advapi32.dll") {
52 m_rtlgenrandom = m_advapi.resolve<RtlGenRandom_fptr>(
"SystemFunction036");
55 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
56 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
57 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
58 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
60 bool is_seeded()
const override {
return true; }
62 bool accepts_input()
const override {
return false; }
64 void clear()
override {
67 std::string name()
const override {
return "RtlGenRandom"; }
70 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
71 const size_t limit = std::numeric_limits<ULONG>::max();
73 uint8_t* pData = output.data();
74 size_t bytesLeft = output.size();
75 while(bytesLeft > 0) {
76 const ULONG blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
78 const bool success = m_rtlgenrandom(pData, blockSize) == TRUE;
80 throw System_Error(
"RtlGenRandom failed");
83 BOTAN_ASSERT(bytesLeft >= blockSize,
"Block is oversized");
84 bytesLeft -= blockSize;
90 using RtlGenRandom_fptr = BOOLEAN(NTAPI*)(PVOID, ULONG);
92 Dynamically_Loaded_Library m_advapi;
93 RtlGenRandom_fptr m_rtlgenrandom;
96#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
101 auto ret = ::BCryptOpenAlgorithmProvider(&m_prov, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
102 if(!BCRYPT_SUCCESS(ret)) {
103 throw System_Error(
"System_RNG failed to acquire crypto provider", ret);
107 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
108 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
109 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
110 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
112 ~System_RNG_Impl()
override { ::BCryptCloseAlgorithmProvider(m_prov, 0); }
114 bool is_seeded()
const override {
return true; }
116 bool accepts_input()
const override {
return false; }
118 void clear()
override {
121 std::string name()
const override {
return "crypto_ng"; }
124 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
130 const size_t limit = std::numeric_limits<ULONG>::max();
132 uint8_t* pData = output.data();
133 size_t bytesLeft = output.size();
134 while(bytesLeft > 0) {
135 const ULONG blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
137 auto ret = BCryptGenRandom(m_prov,
static_cast<PUCHAR
>(pData), blockSize, 0);
138 if(!BCRYPT_SUCCESS(ret)) {
139 throw System_Error(
"System_RNG call to BCryptGenRandom failed", ret);
142 BOTAN_ASSERT(bytesLeft >= blockSize,
"Block is oversized");
143 bytesLeft -= blockSize;
149 BCRYPT_ALG_HANDLE m_prov;
152#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
156 bool accepts_input()
const override {
return false; }
158 bool is_seeded()
const override {
return true; }
160 void clear()
override {
163 std::string name()
const override {
return "CCRandomGenerateBytes"; }
166 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
167 if(::CCRandomGenerateBytes(output.data(), output.size()) != kCCSuccess) {
168 throw System_Error(
"System_RNG CCRandomGenerateBytes failed", errno);
173#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
179 bool accepts_input()
const override {
return false; }
181 bool is_seeded()
const override {
return true; }
183 void clear()
override {
186 std::string name()
const override {
return "arc4random"; }
189 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
193 if(!output.empty()) {
194 ::arc4random_buf(output.data(), output.size());
199#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
205 bool accepts_input()
const override {
return false; }
207 bool is_seeded()
const override {
return true; }
209 void clear()
override {
212 std::string name()
const override {
return "getrandom"; }
215 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
216 const unsigned int flags = 0;
218 uint8_t* buf = output.data();
219 size_t len = output.size();
221 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 25
222 const ssize_t got = ::syscall(SYS_getrandom, buf, len, flags);
224 const ssize_t got = ::getrandom(buf, len, flags);
231 throw System_Error(
"System_RNG getrandom failed", errno);
235 throw System_Error(
"System_RNG getrandom unexpectedly returned 0");
244#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
259 m_fd = ::open(
"/dev/random", O_RDONLY | O_NOCTTY);
261 throw System_Error(
"System_RNG failed to open RNG device", errno);
264 const size_t got = ::read(m_fd, &b, 1);
268 throw System_Error(
"System_RNG failed to read blocking RNG device");
270 m_fd = ::open(
"/dev/urandom", O_RDWR | O_NOCTTY);
279 m_fd = ::open(
"/dev/urandom", O_RDONLY | O_NOCTTY);
284 throw System_Error(
"System_RNG failed to open RNG device", errno);
287 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
288 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
289 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
290 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
292 ~System_RNG_Impl()
override {
297 bool is_seeded()
const override {
return true; }
299 bool accepts_input()
const override {
return m_writable; }
301 void clear()
override {
304 std::string name()
const override {
return "urandom"; }
307 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override;
308 void maybe_write_entropy(std::span<const uint8_t> input);
315void System_RNG_Impl::fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
316 maybe_write_entropy(input);
318 uint8_t* buf = output.data();
319 size_t len = output.size();
321 ssize_t got = ::read(m_fd, buf, len);
336void System_RNG_Impl::maybe_write_entropy(std::span<const uint8_t> entropy_input) {
337 if(!m_writable || entropy_input.empty())
340 const uint8_t* input = entropy_input.data();
341 size_t len = entropy_input.size();
343 ssize_t got = ::write(m_fd, input, len);
361 if(errno == EPERM || errno == EBADF)
378 static System_RNG_Impl g_system_rng;
#define BOTAN_ASSERT(expr, assertion_made)
RandomNumberGenerator & system_rng()