15b223b4278eb762ea0f14c311dc35e03cb1ecf8
[trex.git] /
1
2 #include <sys/types.h>
3 #ifndef _WIN32
4 # include <sys/stat.h>
5 # include <sys/time.h>
6 #endif
7
8 #include <assert.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #ifndef _WIN32
16 # include <unistd.h>
17 #endif
18
19 #include "randombytes.h"
20 #include "randombytes_sysrandom.h"
21 #include "utils.h"
22
23 #ifdef _WIN32
24 # include <windows.h>
25 # define RtlGenRandom SystemFunction036
26 # if defined(__cplusplus)
27 extern "C"
28 # endif
29 BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
30 # pragma comment(lib, "advapi32.lib")
31 #endif
32
33 #ifdef __OpenBSD__
34
35 uint32_t
36 randombytes_sysrandom(void)
37 {
38     return arc4random();
39 }
40
41 void
42 randombytes_sysrandom_stir(void)
43 {
44 }
45
46 uint32_t
47 randombytes_sysrandom_uniform(const uint32_t upper_bound)
48 {
49     return arc4random_uniform(upper_bound);
50 }
51
52 void
53 randombytes_sysrandom_buf(void * const buf, const size_t size)
54 {
55     return arc4random_buf(buf, size);
56 }
57
58 int
59 randombytes_sysrandom_close(void)
60 {
61     return 0;
62 }
63
64 #else /* __OpenBSD__ */
65
66 typedef struct SysRandom_ {
67     int        random_data_source_fd;
68     int        initialized;
69 } SysRandom;
70
71 static SysRandom stream = {
72     SODIUM_C99(.random_data_source_fd =) -1,
73     SODIUM_C99(.initialized =) 0
74 };
75
76 #ifndef _WIN32
77 static ssize_t
78 safe_read(const int fd, void * const buf_, size_t count)
79 {
80     unsigned char *buf = (unsigned char *) buf_;
81     ssize_t        readnb;
82
83     assert(count > (size_t) 0U);
84     do {
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 */
89         }
90         if (readnb == (ssize_t) 0) {
91             break; /* LCOV_EXCL_LINE */
92         }
93         count -= (size_t) readnb;
94         buf += readnb;
95     } while (count > (ssize_t) 0);
96
97     return (ssize_t) (buf - (unsigned char *) buf_);
98 }
99 #endif
100
101 #ifndef _WIN32
102 static int
103 randombytes_sysrandom_random_dev_open(void)
104 {
105 /* LCOV_EXCL_START */
106     struct stat        st;
107     static const char *devices[] = {
108 # ifndef USE_BLOCKING_RANDOM
109         "/dev/urandom",
110 # endif
111         "/dev/random", NULL
112     };
113     const char **      device = devices;
114     int                fd;
115
116     do {
117         fd = open(*device, O_RDONLY);
118         if (fd != -1) {
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);
122 # endif
123                 return fd;
124             }
125             (void) close(fd);
126         } else if (errno == EINTR) {
127             continue;
128         }
129         device++;
130     } while (*device != NULL);
131
132     errno = EIO;
133     return -1;
134 /* LCOV_EXCL_STOP */
135 }
136
137 static void
138 randombytes_sysrandom_init(void)
139 {
140     const int errno_save = errno;
141
142     if ((stream.random_data_source_fd =
143          randombytes_sysrandom_random_dev_open()) == -1) {
144         abort(); /* LCOV_EXCL_LINE */
145     }
146     errno = errno_save;
147 }
148
149 #else /* _WIN32 */
150
151 static void
152 randombytes_sysrandom_init(void)
153 {
154 }
155 #endif
156
157 void
158 randombytes_sysrandom_stir(void)
159 {
160     if (stream.initialized == 0) {
161         randombytes_sysrandom_init();
162         stream.initialized = 1;
163     }
164 }
165
166 static void
167 randombytes_sysrandom_stir_if_needed(void)
168 {
169     if (stream.initialized == 0) {
170         randombytes_sysrandom_stir();
171     }
172 }
173
174 int
175 randombytes_sysrandom_close(void)
176 {
177     int ret = -1;
178
179 #ifndef _WIN32
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;
184         ret = 0;
185     }
186 #else /* _WIN32 */
187     if (stream.initialized != 0) {
188         stream.initialized = 0;
189         ret = 0;
190     }
191 #endif
192     return ret;
193 }
194
195 uint32_t
196 randombytes_sysrandom(void)
197 {
198     uint32_t r;
199
200     randombytes_sysrandom_buf(&r, sizeof r);
201
202     return r;
203 }
204
205 void
206 randombytes_sysrandom_buf(void * const buf, const size_t size)
207 {
208     randombytes_sysrandom_stir_if_needed();
209 #ifdef ULONG_LONG_MAX
210     /* coverity[result_independent_of_operands] */
211     assert(size <= ULONG_LONG_MAX);
212 #endif
213 #ifndef _WIN32
214     if (safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) {
215         abort(); /* LCOV_EXCL_LINE */
216     }
217 #else
218     if (size > (size_t) 0xffffffff) {
219         abort(); /* LCOV_EXCL_LINE */
220     }
221     if (! RtlGenRandom((PVOID) buf, (ULONG) size)) {
222         abort(); /* LCOV_EXCL_LINE */
223     }
224 #endif
225 }
226
227 /*
228  * randombytes_sysrandom_uniform() derives from OpenBSD's arc4random_uniform()
229  * Copyright (c) 2008, Damien Miller <[email protected]>
230  */
231
232 uint32_t
233 randombytes_sysrandom_uniform(const uint32_t upper_bound)
234 {
235     uint32_t min;
236     uint32_t r;
237
238     if (upper_bound < 2) {
239         return 0;
240     }
241     min = (uint32_t) (-upper_bound % upper_bound);
242     for (;;) {
243         r = randombytes_sysrandom();
244         if (r >= min) {
245             break;
246         }
247     } /* LCOV_EXCL_LINE */
248     return r % upper_bound;
249 }
250
251 #endif
252
253 const char *
254 randombytes_sysrandom_implementation_name(void)
255 {
256     return "sysrandom";
257 }
258
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
266 };