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);
240#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
255 m_fd = ::open(
"/dev/random", O_RDONLY | O_NOCTTY);
257 throw System_Error(
"System_RNG failed to open RNG device", errno);
260 const size_t got = ::read(m_fd, &b, 1);
264 throw System_Error(
"System_RNG failed to read blocking RNG device");
266 m_fd = ::open(
"/dev/urandom", O_RDWR | O_NOCTTY);
275 m_fd = ::open(
"/dev/urandom", O_RDONLY | O_NOCTTY);
280 throw System_Error(
"System_RNG failed to open RNG device", errno);
283 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
284 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
285 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
286 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
288 ~System_RNG_Impl()
override {
293 bool is_seeded()
const override {
return true; }
295 bool accepts_input()
const override {
return m_writable; }
297 void clear()
override {
300 std::string name()
const override {
return "urandom"; }
303 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override;
304 void maybe_write_entropy(std::span<const uint8_t> input);
311void System_RNG_Impl::fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
312 maybe_write_entropy(input);
314 uint8_t* buf = output.data();
315 size_t len = output.size();
317 ssize_t got = ::read(m_fd, buf, len);
332void System_RNG_Impl::maybe_write_entropy(std::span<const uint8_t> entropy_input) {
333 if(!m_writable || entropy_input.empty())
336 const uint8_t* input = entropy_input.data();
337 size_t len = entropy_input.size();
339 ssize_t got = ::write(m_fd, input, len);
357 if(errno == EPERM || errno == EBADF)
374 static System_RNG_Impl g_system_rng;
#define BOTAN_ASSERT(expr, assertion_made)
RandomNumberGenerator & system_rng()