9#include <botan/system_rng.h>
11#if defined(BOTAN_TARGET_OS_HAS_WIN32)
17#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
18 #include <botan/internal/dyn_load.h>
19#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
22#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
23 #include <CommonCrypto/CommonRandom.h>
24#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
26#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
28 #include <sys/random.h>
29 #include <sys/syscall.h>
31#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
41#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
43class System_RNG_Impl
final :
public RandomNumberGenerator {
45 System_RNG_Impl() : m_advapi(
"advapi32.dll") {
47 m_rtlgenrandom = m_advapi.resolve<RtlGenRandom_fptr>(
"SystemFunction036");
50 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
51 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
52 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
53 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
55 bool is_seeded()
const override {
return true; }
57 bool accepts_input()
const override {
return false; }
59 void clear()
override {
62 std::string
name()
const override {
return "RtlGenRandom"; }
65 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
66 const size_t limit = std::numeric_limits<ULONG>::max();
68 uint8_t* pData = output.data();
69 size_t bytesLeft = output.size();
70 while(bytesLeft > 0) {
71 const ULONG
blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
73 const bool success = m_rtlgenrandom(pData,
blockSize) ==
TRUE;
75 throw System_Error(
"RtlGenRandom failed");
85 using RtlGenRandom_fptr = BOOLEAN(NTAPI*)(PVOID, ULONG);
87 Dynamically_Loaded_Library m_advapi;
88 RtlGenRandom_fptr m_rtlgenrandom;
91#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
93class System_RNG_Impl
final :
public RandomNumberGenerator {
96 auto ret = ::BCryptOpenAlgorithmProvider(&m_prov, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
97 if(!BCRYPT_SUCCESS(ret)) {
98 throw System_Error(
"System_RNG failed to acquire crypto provider", ret);
102 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
103 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
104 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
105 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
107 ~System_RNG_Impl()
override { ::BCryptCloseAlgorithmProvider(m_prov, 0); }
109 bool is_seeded()
const override {
return true; }
111 bool accepts_input()
const override {
return false; }
113 void clear()
override {
116 std::string
name()
const override {
return "crypto_ng"; }
119 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
125 const size_t limit = std::numeric_limits<ULONG>::max();
127 uint8_t* pData = output.data();
128 size_t bytesLeft = output.size();
129 while(bytesLeft > 0) {
130 const ULONG
blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
132 auto ret = BCryptGenRandom(m_prov,
static_cast<PUCHAR
>(pData),
blockSize, 0);
133 if(!BCRYPT_SUCCESS(ret)) {
134 throw System_Error(
"System_RNG call to BCryptGenRandom failed", ret);
144 BCRYPT_ALG_HANDLE m_prov;
147#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
149class System_RNG_Impl
final :
public RandomNumberGenerator {
151 bool accepts_input()
const override {
return false; }
153 bool is_seeded()
const override {
return true; }
155 void clear()
override {
158 std::string
name()
const override {
return "CCRandomGenerateBytes"; }
161 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
162 if(::CCRandomGenerateBytes(output.data(), output.size()) != kCCSuccess) {
163 throw System_Error(
"System_RNG CCRandomGenerateBytes failed", errno);
168#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
170class System_RNG_Impl
final :
public RandomNumberGenerator {
174 bool accepts_input()
const override {
return false; }
176 bool is_seeded()
const override {
return true; }
178 void clear()
override {
181 std::string
name()
const override {
return "arc4random"; }
184 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
188 if(!output.empty()) {
189 ::arc4random_buf(output.data(), output.size());
194#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
196class System_RNG_Impl
final :
public RandomNumberGenerator {
200 bool accepts_input()
const override {
return false; }
202 bool is_seeded()
const override {
return true; }
204 void clear()
override {
207 std::string
name()
const override {
return "getrandom"; }
210 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override {
211 const unsigned int flags = 0;
213 uint8_t* buf = output.data();
214 size_t len = output.size();
216 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 25
217 const ssize_t got = ::syscall(SYS_getrandom, buf, len, flags);
219 const ssize_t got = ::getrandom(buf, len, flags);
226 throw System_Error(
"System_RNG getrandom failed", errno);
235#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
239class System_RNG_Impl
final :
public RandomNumberGenerator {
250 m_fd = ::open(
"/dev/random", O_RDONLY | O_NOCTTY);
252 throw System_Error(
"System_RNG failed to open RNG device", errno);
255 const size_t got = ::read(m_fd, &b, 1);
259 throw System_Error(
"System_RNG failed to read blocking RNG device");
261 m_fd = ::open(
"/dev/urandom", O_RDWR | O_NOCTTY);
270 m_fd = ::open(
"/dev/urandom", O_RDONLY | O_NOCTTY);
275 throw System_Error(
"System_RNG failed to open RNG device", errno);
278 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
279 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
280 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
281 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
283 ~System_RNG_Impl()
override {
288 bool is_seeded()
const override {
return true; }
290 bool accepts_input()
const override {
return m_writable; }
292 void clear()
override {
295 std::string
name()
const override {
return "urandom"; }
298 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override;
299 void maybe_write_entropy(std::span<const uint8_t> input);
306void System_RNG_Impl::fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
307 maybe_write_entropy(input);
309 uint8_t* buf = output.data();
310 size_t len = output.size();
312 ssize_t got = ::read(m_fd, buf, len);
317 throw System_Error(
"System_RNG read failed", errno);
320 throw System_Error(
"System_RNG EOF on device");
327void System_RNG_Impl::maybe_write_entropy(std::span<const uint8_t> entropy_input) {
328 if(!m_writable || entropy_input.empty())
331 const uint8_t* input = entropy_input.data();
332 size_t len = entropy_input.size();
334 ssize_t got = ::write(m_fd, input, len);
352 if(errno == EPERM || errno == EBADF)
356 throw System_Error(
"System_RNG write failed", errno);
369 static System_RNG_Impl g_system_rng;
#define BOTAN_ASSERT(expr, assertion_made)
int(* final)(unsigned char *, CTX *)
RandomNumberGenerator & system_rng()