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)
27 #include <sys/random.h>
29#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
39#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
41class System_RNG_Impl
final :
public RandomNumberGenerator
44 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; }
56 bool accepts_input()
const override {
return false; }
57 void clear()
override { }
58 std::string
name()
const override {
return "RtlGenRandom"; }
61 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override
63 const size_t limit = std::numeric_limits<ULONG>::max();
65 uint8_t* pData = output.data();
66 size_t bytesLeft = output.size();
69 const ULONG
blockSize =
static_cast<ULONG
>(std::min(bytesLeft, limit));
71 const bool success = m_rtlgenrandom(pData,
blockSize) ==
TRUE;
74 throw System_Error(
"RtlGenRandom failed");
84 using RtlGenRandom_fptr = BOOLEAN (NTAPI *)(PVOID, ULONG);
86 Dynamically_Loaded_Library m_advapi;
87 RtlGenRandom_fptr m_rtlgenrandom;
90#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
92class System_RNG_Impl
final :
public RandomNumberGenerator
97 auto ret = ::BCryptOpenAlgorithmProvider(&m_prov,
99 MS_PRIMITIVE_PROVIDER, 0);
100 if(!BCRYPT_SUCCESS(ret))
102 throw System_Error(
"System_RNG failed to acquire crypto provider", ret);
106 System_RNG_Impl(
const System_RNG_Impl& other) =
delete;
107 System_RNG_Impl(System_RNG_Impl&& other) =
delete;
108 System_RNG_Impl& operator=(
const System_RNG_Impl& other) =
delete;
109 System_RNG_Impl& operator=(System_RNG_Impl&& other) =
delete;
111 ~System_RNG_Impl()
override
113 ::BCryptCloseAlgorithmProvider(m_prov, 0);
116 bool is_seeded()
const override {
return true; }
117 bool accepts_input()
const override {
return false; }
118 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
129 const size_t limit = std::numeric_limits<ULONG>::max();
131 uint8_t* pData = output.data();
132 size_t bytesLeft = output.size();
133 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))
140 throw System_Error(
"System_RNG call to BCryptGenRandom failed", ret);
150 BCRYPT_ALG_HANDLE m_prov;
153#elif defined(BOTAN_TARGET_OS_HAS_CCRANDOM)
155class System_RNG_Impl
final :
public RandomNumberGenerator
158 bool accepts_input()
const override {
return false; }
159 bool is_seeded()
const override {
return true; }
160 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
166 if (::CCRandomGenerateBytes(output.data(), output.size()) != kCCSuccess)
168 throw System_Error(
"System_RNG CCRandomGenerateBytes failed", errno);
173#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
175class System_RNG_Impl
final :
public RandomNumberGenerator
180 bool accepts_input()
const override {
return false; }
181 bool is_seeded()
const override {
return true; }
182 void clear()
override { }
183 std::string
name()
const override {
return "arc4random"; }
186 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override
193 ::arc4random_buf(output.data(), output.size());
198#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
200class System_RNG_Impl
final :
public RandomNumberGenerator
205 bool accepts_input()
const override {
return false; }
206 bool is_seeded()
const override {
return true; }
207 void clear()
override { }
208 std::string
name()
const override {
return "getrandom"; }
211 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override
213 const unsigned int flags = 0;
215 uint8_t* buf = output.data();
216 size_t len = output.size();
219 const ssize_t got = ::getrandom(buf, len, flags);
225 throw System_Error(
"System_RNG getrandom failed", errno);
235#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
239class System_RNG_Impl
final :
public RandomNumberGenerator
252 m_fd = ::open(
"/dev/random", O_RDONLY | O_NOCTTY);
254 throw System_Error(
"System_RNG failed to open RNG device", errno);
257 const size_t got = ::read(m_fd, &b, 1);
261 throw System_Error(
"System_RNG failed to read blocking RNG device");
263 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
294 bool is_seeded()
const override {
return true; }
295 bool accepts_input()
const override {
return m_writable; }
296 void clear()
override { }
297 std::string
name()
const override {
return "urandom"; }
300 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> )
override;
301 void maybe_write_entropy(std::span<const uint8_t> input);
308void 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();
316 ssize_t got = ::read(m_fd, buf, len);
322 throw System_Error(
"System_RNG read failed", errno);
325 throw System_Error(
"System_RNG EOF on device");
332void System_RNG_Impl::maybe_write_entropy(std::span<const uint8_t> entropy_input)
334 if(!m_writable || entropy_input.empty())
337 const uint8_t* input = entropy_input.data();
338 size_t len = entropy_input.size();
341 ssize_t got = ::write(m_fd, input, len);
360 if(errno == EPERM || errno == EBADF)
364 throw System_Error(
"System_RNG write failed", errno);
378 static System_RNG_Impl g_system_rng;
#define BOTAN_ASSERT(expr, assertion_made)
int(* final)(unsigned char *, CTX *)
RandomNumberGenerator & system_rng()