libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / libsodium / src / libsodium / randombytes / sysrandom / randombytes_sysrandom.c
blob84a1c857e85216ae360b982e5472a0b88c8e5d42
2 #include <sys/types.h>
3 #include <sys/time.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <limits.h>
9 #ifndef _WIN32
10 # include <poll.h>
11 #endif
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
18 #include "randombytes.h"
19 #include "randombytes_sysrandom.h"
20 #include "utils.h"
22 #ifdef _WIN32
23 # include <Windows.h>
24 # include <Wincrypt.h>
25 #endif
27 typedef struct SysRandom_ {
28 #ifdef _WIN32
29 HCRYPTPROV hcrypt_prov;
30 #endif
31 int random_data_source_fd;
32 bool initialized;
33 } SysRandom;
35 static SysRandom stream = {
36 _SODIUM_C99(.random_data_source_fd =) -1,
37 _SODIUM_C99(.initialized =) 0
40 #ifndef _WIN32
41 static ssize_t
42 safe_read(const int fd, void * const buf_, size_t count)
44 unsigned char *buf = (unsigned char *) buf_;
45 ssize_t readnb;
47 do {
48 while ((readnb = read(fd, buf, count)) < (ssize_t) 0 &&
49 errno == EINTR);
50 if (readnb < (ssize_t) 0) {
51 return readnb;
53 if (readnb == (ssize_t) 0) {
54 break;
56 count -= (size_t) readnb;
57 buf += readnb;
58 } while (count > (ssize_t) 0);
60 return (ssize_t) (buf - (unsigned char *) buf_);
62 #endif
64 #ifndef _WIN32
65 static int
66 randombytes_sysrandom_random_dev_open(void)
68 static const char * const devices[] = {
69 # ifndef USE_BLOCKING_RANDOM
70 "/dev/arandom", "/dev/urandom",
71 # endif
72 "/dev/random", NULL
74 const char * const *device = devices;
76 do {
77 if (access(*device, F_OK | R_OK) == 0) {
78 return open(*device, O_RDONLY);
80 device++;
81 } while (*device != NULL);
83 return -1;
86 static void
87 randombytes_sysrandom_init(void)
89 if ((stream.random_data_source_fd =
90 randombytes_sysrandom_random_dev_open()) == -1) {
91 abort();
95 #else /* _WIN32 */
97 static void
98 randombytes_sysrandom_init(void)
100 if (! CryptAcquireContext(&stream.hcrypt_prov, NULL, NULL,
101 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
102 abort();
105 #endif
107 void
108 randombytes_sysrandom_stir(void)
110 if (stream.initialized == 0) {
111 randombytes_sysrandom_init();
112 stream.initialized = 1;
116 static void
117 randombytes_sysrandom_stir_if_needed(void)
119 if (stream.initialized == 0) {
120 randombytes_sysrandom_stir();
125 randombytes_sysrandom_close(void)
127 int ret = -1;
129 #ifndef _WIN32
130 if (stream.random_data_source_fd != -1 &&
131 close(stream.random_data_source_fd) == 0) {
132 stream.random_data_source_fd = -1;
133 stream.initialized = 0;
134 ret = 0;
136 #else /* _WIN32 */
137 if (stream.initialized != 0 &&
138 CryptReleaseContext(stream.hcrypt_prov, 0)) {
139 stream.initialized = 0;
140 ret = 0;
142 #endif
143 return ret;
146 uint32_t
147 randombytes_sysrandom(void)
149 uint32_t r;
151 randombytes_sysrandom_buf(&r, sizeof r);
153 return r;
156 void
157 randombytes_sysrandom_buf(void * const buf, const size_t size)
159 randombytes_sysrandom_stir_if_needed();
160 #ifdef ULONG_LONG_MAX
161 assert(size <= ULONG_LONG_MAX);
162 #endif
163 #ifndef _WIN32
164 if (safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) {
165 abort();
167 #else
168 if (! CryptGenRandom(stream.hcrypt_prov, size, buf)) {
169 abort();
171 #endif
175 * randombytes_sysrandom_uniform() derives from OpenBSD's arc4random_uniform()
176 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
179 uint32_t
180 randombytes_sysrandom_uniform(const uint32_t upper_bound)
182 uint32_t min;
183 uint32_t r;
185 if (upper_bound < 2) {
186 return 0;
188 min = (uint32_t) (-upper_bound % upper_bound);
189 for (;;) {
190 r = randombytes_sysrandom();
191 if (r >= min) {
192 break;
195 return r % upper_bound;
198 const char *
199 randombytes_sysrandom_implementation_name(void)
201 return "sysrandom";
204 struct randombytes_implementation randombytes_sysrandom_implementation = {
205 _SODIUM_C99(.implementation_name =) randombytes_sysrandom_implementation_name,
206 _SODIUM_C99(.random =) randombytes_sysrandom,
207 _SODIUM_C99(.stir =) randombytes_sysrandom_stir,
208 _SODIUM_C99(.uniform =) randombytes_sysrandom_uniform,
209 _SODIUM_C99(.buf =) randombytes_sysrandom_buf,
210 _SODIUM_C99(.close =) randombytes_sysrandom_close