3d7627d242ae13c578f36e8bfde6dd7894a8a3c9
[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 _MSC_VER
16 # include <unistd.h>
17 #endif
18
19 #include "crypto_core_salsa20.h"
20 #include "crypto_auth_hmacsha512256.h"
21 #include "crypto_stream_salsa20.h"
22 #include "randombytes.h"
23 #include "randombytes_salsa20_random.h"
24 #include "utils.h"
25
26 #ifdef _WIN32
27 # include <windows.h>
28 # include <sys/timeb.h>
29 # define RtlGenRandom SystemFunction036
30 # if defined(__cplusplus)
31 extern "C"
32 # endif
33 BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
34 # pragma comment(lib, "advapi32.lib")
35 #endif
36
37 #define SALSA20_RANDOM_BLOCK_SIZE crypto_core_salsa20_OUTPUTBYTES
38 #define SHA512_BLOCK_SIZE 128U
39 #define SHA512_MIN_PAD_SIZE (1U + 16U)
40 #define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1])
41
42 typedef struct Salsa20Random_ {
43     unsigned char key[crypto_stream_salsa20_KEYBYTES];
44     unsigned char rnd32[16U * SALSA20_RANDOM_BLOCK_SIZE];
45     uint64_t      nonce;
46     size_t        rnd32_outleft;
47 #ifndef _MSC_VER
48     pid_t         pid;
49 #endif
50     int           random_data_source_fd;
51     int           initialized;
52 } Salsa20Random;
53
54 static Salsa20Random stream = {
55     SODIUM_C99(.random_data_source_fd =) -1,
56     SODIUM_C99(.rnd32_outleft =) (size_t) 0U,
57     SODIUM_C99(.initialized =) 0
58 };
59
60 static uint64_t
61 sodium_hrtime(void)
62 {
63     struct timeval tv;
64     uint64_t       ts = (uint64_t) 0U;
65     int            ret;
66
67 #ifdef _WIN32
68     struct _timeb tb;
69
70 # pragma warning(push)
71 # pragma warning(disable: 4996)
72     _ftime(&tb);
73 # pragma warning(pop)
74     tv.tv_sec = (long) tb.time;
75     tv.tv_usec = ((int) tb.millitm) * 1000;
76     ret = 0;
77 #else
78     ret = gettimeofday(&tv, NULL);
79 #endif
80     assert(ret == 0);
81     if (ret == 0) {
82         ts = (uint64_t) tv.tv_sec * 1000000U + (uint64_t) tv.tv_usec;
83     }
84     return ts;
85 }
86
87 #ifndef _WIN32
88 static ssize_t
89 safe_read(const int fd, void * const buf_, size_t count)
90 {
91     unsigned char *buf = (unsigned char *) buf_;
92     ssize_t        readnb;
93
94     assert(count > (size_t) 0U);
95     do {
96         while ((readnb = read(fd, buf, count)) < (ssize_t) 0 &&
97                (errno == EINTR || errno == EAGAIN));  /* LCOV_EXCL_LINE */
98         if (readnb < (ssize_t) 0) {
99             return readnb; /* LCOV_EXCL_LINE */
100         }
101         if (readnb == (ssize_t) 0) {
102             break; /* LCOV_EXCL_LINE */
103         }
104         count -= (size_t) readnb;
105         buf += readnb;
106     } while (count > (ssize_t) 0);
107
108     return (ssize_t) (buf - (unsigned char *) buf_);
109 }
110 #endif
111
112 #ifndef _WIN32
113 static int
114 randombytes_salsa20_random_random_dev_open(void)
115 {
116 /* LCOV_EXCL_START */
117     struct stat       st;
118     static const char *devices[] = {
119 # ifndef USE_BLOCKING_RANDOM
120         "/dev/urandom",
121 # endif
122         "/dev/random", NULL
123     };
124     const char **     device = devices;
125     int               fd;
126
127     do {
128         fd = open(*device, O_RDONLY);
129         if (fd != -1) {
130             if (fstat(fd, &st) == 0 && S_ISCHR(st.st_mode)) {
131 # if defined(F_SETFD) && defined(FD_CLOEXEC)
132                 (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
133 # endif
134                 return fd;
135             }
136             (void) close(fd);
137         } else if (errno == EINTR) {
138             continue;
139         }
140         device++;
141     } while (*device != NULL);
142
143     errno = EIO;
144     return -1;
145 /* LCOV_EXCL_STOP */
146 }
147
148 static void
149 randombytes_salsa20_random_init(void)
150 {
151     const int errno_save = errno;
152
153     stream.nonce = sodium_hrtime();
154     assert(stream.nonce != (uint64_t) 0U);
155
156     if ((stream.random_data_source_fd =
157          randombytes_salsa20_random_random_dev_open()) == -1) {
158         abort(); /* LCOV_EXCL_LINE */
159     }
160     errno = errno_save;
161 }
162
163 #else /* _WIN32 */
164
165 static void
166 randombytes_salsa20_random_init(void)
167 {
168     stream.nonce = sodium_hrtime();
169     assert(stream.nonce != (uint64_t) 0U);
170 }
171 #endif
172
173 void
174 randombytes_salsa20_random_stir(void)
175 {
176     const unsigned char s[crypto_auth_hmacsha512256_KEYBYTES] = {
177         'T', 'h', 'i', 's', 'I', 's', 'J', 'u', 's', 't', 'A', 'T',
178         'h', 'i', 'r', 't', 'y', 'T', 'w', 'o', 'B', 'y', 't', 'e',
179         's', 'S', 'e', 'e', 'd', '.', '.', '.'
180     };
181     unsigned char  m0[crypto_auth_hmacsha512256_BYTES +
182                       2U * SHA512_BLOCK_SIZE - SHA512_MIN_PAD_SIZE];
183     unsigned char *k0 = m0 + crypto_auth_hmacsha512256_BYTES;
184     size_t         i;
185     size_t         sizeof_k0 = sizeof m0 - crypto_auth_hmacsha512256_BYTES;
186
187     memset(stream.rnd32, 0, sizeof stream.rnd32);
188     stream.rnd32_outleft = (size_t) 0U;
189     if (stream.initialized == 0) {
190         randombytes_salsa20_random_init();
191         stream.initialized = 1;
192     }
193 #ifndef _WIN32
194     if (safe_read(stream.random_data_source_fd, m0,
195                   sizeof m0) != (ssize_t) sizeof m0) {
196         abort(); /* LCOV_EXCL_LINE */
197     }
198 #else /* _WIN32 */
199     if (! RtlGenRandom((PVOID) m0, (ULONG) sizeof m0)) {
200         abort(); /* LCOV_EXCL_LINE */
201     }
202 #endif
203     COMPILER_ASSERT(sizeof stream.key == crypto_auth_hmacsha512256_BYTES);
204     crypto_auth_hmacsha512256(stream.key, k0, sizeof_k0, s);
205     COMPILER_ASSERT(sizeof stream.key <= sizeof m0);
206     for (i = (size_t) 0U; i < sizeof stream.key; i++) {
207         stream.key[i] ^= m0[i];
208     }
209     sodium_memzero(m0, sizeof m0);
210 }
211
212 static void
213 randombytes_salsa20_random_stir_if_needed(void)
214 {
215 #ifdef _MSC_VER
216     if (stream.initialized == 0) {
217         randombytes_salsa20_random_stir();
218     }
219 #else
220     const pid_t pid = getpid();
221
222     if (stream.initialized == 0 || stream.pid != pid) {
223         stream.pid = pid;
224         randombytes_salsa20_random_stir();
225     }
226 #endif
227 }
228
229 static void
230 randombytes_salsa20_random_rekey(const unsigned char * const mix)
231 {
232     unsigned char *key = stream.key;
233     size_t         i;
234
235     for (i = (size_t) 0U; i < sizeof stream.key; i++) {
236         key[i] ^= mix[i];
237     }
238 }
239
240 static uint32_t
241 randombytes_salsa20_random_getword(void)
242 {
243     uint32_t val;
244     int      ret;
245
246     COMPILER_ASSERT(sizeof stream.rnd32 >= (sizeof stream.key) + (sizeof val));
247     COMPILER_ASSERT(((sizeof stream.rnd32) - (sizeof stream.key))
248                     % sizeof val == (size_t) 0U);
249     if (stream.rnd32_outleft <= (size_t) 0U) {
250         randombytes_salsa20_random_stir_if_needed();
251         COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
252         ret = crypto_stream_salsa20((unsigned char *) stream.rnd32,
253                                     (unsigned long long) sizeof stream.rnd32,
254                                     (unsigned char *) &stream.nonce,
255                                     stream.key);
256         assert(ret == 0);
257         stream.rnd32_outleft = (sizeof stream.rnd32) - (sizeof stream.key);
258         randombytes_salsa20_random_rekey(&stream.rnd32[stream.rnd32_outleft]);
259         stream.nonce++;
260     }
261     stream.rnd32_outleft -= sizeof val;
262     memcpy(&val, &stream.rnd32[stream.rnd32_outleft], sizeof val);
263     memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof val);
264
265     return val;
266 }
267
268 int
269 randombytes_salsa20_random_close(void)
270 {
271     int ret = -1;
272
273 #ifndef _WIN32
274     if (stream.random_data_source_fd != -1 &&
275         close(stream.random_data_source_fd) == 0) {
276         stream.random_data_source_fd = -1;
277         stream.initialized = 0;
278         ret = 0;
279     }
280 #else /* _WIN32 */
281     if (stream.initialized != 0) {
282         stream.initialized = 0;
283         ret = 0;
284     }
285 #endif
286     return ret;
287 }
288
289 uint32_t
290 randombytes_salsa20_random(void)
291 {
292     return randombytes_salsa20_random_getword();
293 }
294
295 void
296 randombytes_salsa20_random_buf(void * const buf, const size_t size)
297 {
298     int ret;
299
300     randombytes_salsa20_random_stir_if_needed();
301     COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
302 #ifdef ULONG_LONG_MAX
303     /* coverity[result_independent_of_operands] */
304     assert(size <= ULONG_LONG_MAX);
305 #endif
306     ret = crypto_stream_salsa20((unsigned char *) buf, (unsigned long long) size,
307                                 (unsigned char *) &stream.nonce, stream.key);
308     assert(ret == 0);
309     stream.nonce++;
310     crypto_stream_salsa20_xor(stream.key, stream.key, sizeof stream.key,
311                               (unsigned char *) &stream.nonce, stream.key);
312 }
313
314 /*
315  * randombytes_salsa20_random_uniform() derives from OpenBSD's arc4random_uniform()
316  * Copyright (c) 2008, Damien Miller <[email protected]>
317  */
318
319 uint32_t
320 randombytes_salsa20_random_uniform(const uint32_t upper_bound)
321 {
322     uint32_t min;
323     uint32_t r;
324
325     if (upper_bound < 2) {
326         return 0;
327     }
328     min = (uint32_t) (-upper_bound % upper_bound);
329     for (;;) {
330         r = randombytes_salsa20_random();
331         if (r >= min) {
332             break;
333         }
334     } /* LCOV_EXCL_LINE */
335     return r % upper_bound;
336 }
337
338 const char *
339 randombytes_salsa20_implementation_name(void)
340 {
341     return "salsa20";
342 }
343
344 struct randombytes_implementation randombytes_salsa20_implementation = {
345     SODIUM_C99(.implementation_name =) randombytes_salsa20_implementation_name,
346     SODIUM_C99(.random =) randombytes_salsa20_random,
347     SODIUM_C99(.stir =) randombytes_salsa20_random_stir,
348     SODIUM_C99(.uniform =) randombytes_salsa20_random_uniform,
349     SODIUM_C99(.buf =) randombytes_salsa20_random_buf,
350     SODIUM_C99(.close =) randombytes_salsa20_random_close
351 };