19 #include "randombytes.h"
20 #include "randombytes_sysrandom.h"
25 # define RtlGenRandom SystemFunction036
26 # if defined(__cplusplus)
29 BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
30 # pragma comment(lib, "advapi32.lib")
36 randombytes_sysrandom(void)
42 randombytes_sysrandom_stir(void)
47 randombytes_sysrandom_uniform(const uint32_t upper_bound)
49 return arc4random_uniform(upper_bound);
53 randombytes_sysrandom_buf(void * const buf, const size_t size)
55 return arc4random_buf(buf, size);
59 randombytes_sysrandom_close(void)
64 #else /* __OpenBSD__ */
66 typedef struct SysRandom_ {
67 int random_data_source_fd;
71 static SysRandom stream = {
72 SODIUM_C99(.random_data_source_fd =) -1,
73 SODIUM_C99(.initialized =) 0
78 safe_read(const int fd, void * const buf_, size_t count)
80 unsigned char *buf = (unsigned char *) buf_;
83 assert(count > (size_t) 0U);
85 while ((readnb = read(fd, buf, count)) < (ssize_t) 0 &&
86 (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */
87 if (readnb < (ssize_t) 0) {
88 return readnb; /* LCOV_EXCL_LINE */
90 if (readnb == (ssize_t) 0) {
91 break; /* LCOV_EXCL_LINE */
93 count -= (size_t) readnb;
95 } while (count > (ssize_t) 0);
97 return (ssize_t) (buf - (unsigned char *) buf_);
103 randombytes_sysrandom_random_dev_open(void)
105 /* LCOV_EXCL_START */
107 static const char *devices[] = {
108 # ifndef USE_BLOCKING_RANDOM
113 const char ** device = devices;
117 fd = open(*device, O_RDONLY);
119 if (fstat(fd, &st) == 0 && S_ISCHR(st.st_mode)) {
120 # if defined(F_SETFD) && defined(FD_CLOEXEC)
121 (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
126 } else if (errno == EINTR) {
130 } while (*device != NULL);
138 randombytes_sysrandom_init(void)
140 const int errno_save = errno;
142 if ((stream.random_data_source_fd =
143 randombytes_sysrandom_random_dev_open()) == -1) {
144 abort(); /* LCOV_EXCL_LINE */
152 randombytes_sysrandom_init(void)
158 randombytes_sysrandom_stir(void)
160 if (stream.initialized == 0) {
161 randombytes_sysrandom_init();
162 stream.initialized = 1;
167 randombytes_sysrandom_stir_if_needed(void)
169 if (stream.initialized == 0) {
170 randombytes_sysrandom_stir();
175 randombytes_sysrandom_close(void)
180 if (stream.random_data_source_fd != -1 &&
181 close(stream.random_data_source_fd) == 0) {
182 stream.random_data_source_fd = -1;
183 stream.initialized = 0;
187 if (stream.initialized != 0) {
188 stream.initialized = 0;
196 randombytes_sysrandom(void)
200 randombytes_sysrandom_buf(&r, sizeof r);
206 randombytes_sysrandom_buf(void * const buf, const size_t size)
208 randombytes_sysrandom_stir_if_needed();
209 #ifdef ULONG_LONG_MAX
210 /* coverity[result_independent_of_operands] */
211 assert(size <= ULONG_LONG_MAX);
214 if (safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) {
215 abort(); /* LCOV_EXCL_LINE */
218 if (size > (size_t) 0xffffffff) {
219 abort(); /* LCOV_EXCL_LINE */
221 if (! RtlGenRandom((PVOID) buf, (ULONG) size)) {
222 abort(); /* LCOV_EXCL_LINE */
228 * randombytes_sysrandom_uniform() derives from OpenBSD's arc4random_uniform()
233 randombytes_sysrandom_uniform(const uint32_t upper_bound)
238 if (upper_bound < 2) {
241 min = (uint32_t) (-upper_bound % upper_bound);
243 r = randombytes_sysrandom();
247 } /* LCOV_EXCL_LINE */
248 return r % upper_bound;
254 randombytes_sysrandom_implementation_name(void)
259 struct randombytes_implementation randombytes_sysrandom_implementation = {
260 SODIUM_C99(.implementation_name =) randombytes_sysrandom_implementation_name,
261 SODIUM_C99(.random =) randombytes_sysrandom,
262 SODIUM_C99(.stir =) randombytes_sysrandom_stir,
263 SODIUM_C99(.uniform =) randombytes_sysrandom_uniform,
264 SODIUM_C99(.buf =) randombytes_sysrandom_buf,
265 SODIUM_C99(.close =) randombytes_sysrandom_close