1
2 #include <assert.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #if !defined(_MSC_VER) && !defined(__BORLANDC__)
11 # include <unistd.h>
12 #endif
13
14 #include <sys/types.h>
15 #ifndef _WIN32
16 # include <sys/stat.h>
17 # include <sys/time.h>
18 #endif
19 #ifdef __linux__
20 # ifdef __dietlibc__
21 # define _LINUX_SOURCE
22 # else
23 # include <sys/syscall.h>
24 # endif
25 # include <poll.h>
26 #endif
27 #ifdef HAVE_RDRAND
28 # pragma GCC target("rdrnd")
29 # include <immintrin.h>
30 #endif
31
32 #include "core.h"
33 #include "crypto_core_salsa20.h"
34 #include "crypto_stream_salsa20.h"
35 #include "private/common.h"
36 #include "randombytes.h"
37 #include "randombytes_salsa20_random.h"
38 #include "runtime.h"
39 #include "utils.h"
40
41 #ifdef _WIN32
42 # include <windows.h>
43 # include <sys/timeb.h>
44 # define RtlGenRandom SystemFunction036
45 # if defined(__cplusplus)
46 extern "C"
47 # endif
48 BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
49 # pragma comment(lib, "advapi32.lib")
50 # ifdef __BORLANDC__
51 # define _ftime ftime
52 # define _timeb timeb
53 # endif
54 #endif
55
56 #define SALSA20_RANDOM_BLOCK_SIZE crypto_core_salsa20_OUTPUTBYTES
57
58 #if defined(__OpenBSD__) || defined(__CloudABI__)
59 # define HAVE_SAFE_ARC4RANDOM 1
60 #endif
61
62 #ifndef SSIZE_MAX
63 # define SSIZE_MAX (SIZE_MAX / 2 - 1)
64 #endif
65 #ifndef S_ISNAM
66 # ifdef __COMPCERT__
67 # define S_ISNAM(X) 1
68 # else
69 # define S_ISNAM(X) 0
70 # endif
71 #endif
72
73 #ifndef TLS
74 # ifdef _WIN32
75 # define TLS __declspec(thread)
76 # else
77 # define TLS
78 # endif
79 #endif
80
81 typedef struct Salsa20RandomGlobal_ {
82 int initialized;
83 int random_data_source_fd;
84 int getrandom_available;
85 int rdrand_available;
86 #ifdef HAVE_GETPID
87 pid_t pid;
88 #endif
89 } Salsa20RandomGlobal;
90
91 typedef struct Salsa20Random_ {
92 int initialized;
93 size_t rnd32_outleft;
94 unsigned char key[crypto_stream_salsa20_KEYBYTES];
95 unsigned char rnd32[16U * SALSA20_RANDOM_BLOCK_SIZE];
96 uint64_t nonce;
97 } Salsa20Random;
98
99 static Salsa20RandomGlobal global = {
100 SODIUM_C99(.initialized =) 0,
101 SODIUM_C99(.random_data_source_fd =) -1
102 };
103
104 static TLS Salsa20Random stream = {
105 SODIUM_C99(.initialized =) 0,
106 SODIUM_C99(.rnd32_outleft =) (size_t) 0U
107 };
108
109
110 /*
111 * Get a high-resolution timestamp, as a uint64_t value
112 */
113
114 #ifdef _WIN32
115 static uint64_t
sodium_hrtime(void)116 sodium_hrtime(void)
117 {
118 struct _timeb tb;
119 # pragma warning(push)
120 # pragma warning(disable: 4996)
121 _ftime(&tb);
122 # pragma warning(pop)
123 return ((uint64_t) tb.time) * 1000000U + ((uint64_t) tb.millitm) * 1000U;
124 }
125
126 #else /* _WIN32 */
127
128 static uint64_t
sodium_hrtime(void)129 sodium_hrtime(void)
130 {
131 struct timeval tv;
132
133 if (gettimeofday(&tv, NULL) != 0) {
134 sodium_misuse(); /* LCOV_EXCL_LINE */
135 }
136 return ((uint64_t) tv.tv_sec) * 1000000U + (uint64_t) tv.tv_usec;
137 }
138 #endif
139
140 /*
141 * Initialize the entropy source
142 */
143
144 #ifdef _WIN32
145
146 static void
randombytes_salsa20_random_init(void)147 randombytes_salsa20_random_init(void)
148 {
149 stream.nonce = sodium_hrtime();
150 assert(stream.nonce != (uint64_t) 0U);
151 global.rdrand_available = sodium_runtime_has_rdrand();
152 }
153
154 #else /* _WIN32 */
155
156 static ssize_t
safe_read(const int fd,void * const buf_,size_t size)157 safe_read(const int fd, void * const buf_, size_t size)
158 {
159 unsigned char *buf = (unsigned char *) buf_;
160 ssize_t readnb;
161
162 assert(size > (size_t) 0U);
163 assert(size <= SSIZE_MAX);
164 do {
165 while ((readnb = read(fd, buf, size)) < (ssize_t) 0 &&
166 (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */
167 if (readnb < (ssize_t) 0) {
168 return readnb; /* LCOV_EXCL_LINE */
169 }
170 if (readnb == (ssize_t) 0) {
171 break; /* LCOV_EXCL_LINE */
172 }
173 size -= (size_t) readnb;
174 buf += readnb;
175 } while (size > (ssize_t) 0);
176
177 return (ssize_t) (buf - (unsigned char *) buf_);
178 }
179
180 # if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL)
181 static int
randombytes_block_on_dev_random(void)182 randombytes_block_on_dev_random(void)
183 {
184 struct pollfd pfd;
185 int fd;
186 int pret;
187
188 fd = open("/dev/random", O_RDONLY);
189 if (fd == -1) {
190 return 0;
191 }
192 pfd.fd = fd;
193 pfd.events = POLLIN;
194 pfd.revents = 0;
195 do {
196 pret = poll(&pfd, 1, -1);
197 } while (pret < 0 && (errno == EINTR || errno == EAGAIN));
198 if (pret != 1) {
199 (void) close(fd);
200 errno = EIO;
201 return -1;
202 }
203 return close(fd);
204 }
205 # endif
206
207 # ifndef HAVE_SAFE_ARC4RANDOM
208 static int
randombytes_salsa20_random_random_dev_open(void)209 randombytes_salsa20_random_random_dev_open(void)
210 {
211 /* LCOV_EXCL_START */
212 struct stat st;
213 static const char *devices[] = {
214 # ifndef USE_BLOCKING_RANDOM
215 "/dev/urandom",
216 # endif
217 "/dev/random", NULL
218 };
219 const char **device = devices;
220 int fd;
221
222 # if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL)
223 if (randombytes_block_on_dev_random() != 0) {
224 return -1;
225 }
226 # endif
227 do {
228 fd = open(*device, O_RDONLY);
229 if (fd != -1) {
230 if (fstat(fd, &st) == 0 && (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))) {
231 # if defined(F_SETFD) && defined(FD_CLOEXEC)
232 (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
233 # endif
234 return fd;
235 }
236 (void) close(fd);
237 } else if (errno == EINTR) {
238 continue;
239 }
240 device++;
241 } while (*device != NULL);
242
243 errno = EIO;
244 return -1;
245 /* LCOV_EXCL_STOP */
246 }
247 # endif
248
249 # if defined(__dietlibc__) || (defined(SYS_getrandom) && defined(__NR_getrandom))
250 static int
_randombytes_linux_getrandom(void * const buf,const size_t size)251 _randombytes_linux_getrandom(void * const buf, const size_t size)
252 {
253 int readnb;
254
255 assert(size <= 256U);
256 do {
257 # ifdef __dietlibc__
258 readnb = getrandom(buf, size, 0);
259 # else
260 readnb = syscall(SYS_getrandom, buf, (int) size, 0);
261 # endif
262 } while (readnb < 0 && (errno == EINTR || errno == EAGAIN));
263
264 return (readnb == (int) size) - 1;
265 }
266
267 static int
randombytes_linux_getrandom(void * const buf_,size_t size)268 randombytes_linux_getrandom(void * const buf_, size_t size)
269 {
270 unsigned char *buf = (unsigned char *) buf_;
271 size_t chunk_size = 256U;
272
273 do {
274 if (size < chunk_size) {
275 chunk_size = size;
276 assert(chunk_size > (size_t) 0U);
277 }
278 if (_randombytes_linux_getrandom(buf, chunk_size) != 0) {
279 return -1;
280 }
281 size -= chunk_size;
282 buf += chunk_size;
283 } while (size > (size_t) 0U);
284
285 return 0;
286 }
287 # endif
288
289 static void
randombytes_salsa20_random_init(void)290 randombytes_salsa20_random_init(void)
291 {
292 const int errno_save = errno;
293
294 stream.nonce = sodium_hrtime();
295 global.rdrand_available = sodium_runtime_has_rdrand();
296 assert(stream.nonce != (uint64_t) 0U);
297
298 # ifdef HAVE_SAFE_ARC4RANDOM
299 errno = errno_save;
300 # else
301
302 # if defined(SYS_getrandom) && defined(__NR_getrandom)
303 {
304 unsigned char fodder[16];
305
306 if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) {
307 global.getrandom_available = 1;
308 errno = errno_save;
309 return;
310 }
311 global.getrandom_available = 0;
312 }
313 # endif /* SYS_getrandom */
314
315 if ((global.random_data_source_fd =
316 randombytes_salsa20_random_random_dev_open()) == -1) {
317 sodium_misuse(); /* LCOV_EXCL_LINE */
318 }
319 errno = errno_save;
320 # endif /* HAVE_SAFE_ARC4RANDOM */
321 }
322
323 #endif /* _WIN32 */
324
325 /*
326 * (Re)seed the generator using the entropy source
327 */
328
329 static void
randombytes_salsa20_random_stir(void)330 randombytes_salsa20_random_stir(void)
331 {
332 memset(stream.rnd32, 0, sizeof stream.rnd32);
333 stream.rnd32_outleft = (size_t) 0U;
334 if (global.initialized == 0) {
335 randombytes_salsa20_random_init();
336 global.initialized = 1;
337 }
338 #ifdef HAVE_GETPID
339 global.pid = getpid();
340 #endif
341
342 #ifndef _WIN32
343
344 # ifdef HAVE_SAFE_ARC4RANDOM
345 arc4random_buf(stream.key, sizeof stream.key);
346 # elif defined(SYS_getrandom) && defined(__NR_getrandom)
347 if (global.getrandom_available != 0) {
348 if (randombytes_linux_getrandom(stream.key, sizeof stream.key) != 0) {
349 sodium_misuse(); /* LCOV_EXCL_LINE */
350 }
351 } else if (global.random_data_source_fd == -1 ||
352 safe_read(global.random_data_source_fd, stream.key,
353 sizeof stream.key) != (ssize_t) sizeof stream.key) {
354 sodium_misuse(); /* LCOV_EXCL_LINE */
355 }
356 # else
357 if (global.random_data_source_fd == -1 ||
358 safe_read(global.random_data_source_fd, stream.key,
359 sizeof stream.key) != (ssize_t) sizeof stream.key) {
360 sodium_misuse(); /* LCOV_EXCL_LINE */
361 }
362 # endif
363
364 #else /* _WIN32 */
365 if (! RtlGenRandom((PVOID) stream.key, (ULONG) sizeof stream.key)) {
366 sodium_misuse(); /* LCOV_EXCL_LINE */
367 }
368 #endif
369
370 stream.initialized = 1;
371 }
372
373 /*
374 * Reseed the generator if it hasn't been initialized yet
375 */
376
377 static void
randombytes_salsa20_random_stir_if_needed(void)378 randombytes_salsa20_random_stir_if_needed(void)
379 {
380 #ifdef HAVE_GETPID
381 if (stream.initialized == 0) {
382 randombytes_salsa20_random_stir();
383 } else if (global.pid != getpid()) {
384 sodium_misuse(); /* LCOV_EXCL_LINE */
385 }
386 #else
387 if (stream.initialized == 0) {
388 randombytes_salsa20_random_stir();
389 }
390 #endif
391 }
392
393 /*
394 * Close the stream, free global resources
395 */
396
397 #ifdef _WIN32
398 static int
randombytes_salsa20_random_close(void)399 randombytes_salsa20_random_close(void)
400 {
401 int ret = -1;
402
403 if (global.initialized != 0) {
404 global.initialized = 0;
405 ret = 0;
406 }
407 sodium_memzero(&stream, sizeof stream);
408
409 return ret;
410 }
411 #else
412 static int
randombytes_salsa20_random_close(void)413 randombytes_salsa20_random_close(void)
414 {
415 int ret = -1;
416
417 if (global.random_data_source_fd != -1 &&
418 close(global.random_data_source_fd) == 0) {
419 global.random_data_source_fd = -1;
420 global.initialized = 0;
421 # ifdef HAVE_GETPID
422 global.pid = (pid_t) 0;
423 # endif
424 ret = 0;
425 }
426
427 # ifdef HAVE_SAFE_ARC4RANDOM
428 ret = 0;
429 # endif
430
431 # if defined(SYS_getrandom) && defined(__NR_getrandom)
432 if (global.getrandom_available != 0) {
433 ret = 0;
434 }
435 # endif
436
437 sodium_memzero(&stream, sizeof stream);
438
439 return ret;
440 }
441 #endif
442
443 /*
444 * RDRAND is only used to mitigate prediction if a key is compromised
445 */
446
447 static void
randombytes_salsa20_random_xorhwrand(void)448 randombytes_salsa20_random_xorhwrand(void)
449 {
450 /* LCOV_EXCL_START */
451 #ifdef HAVE_RDRAND
452 unsigned int r;
453
454 if (global.rdrand_available == 0) {
455 return;
456 }
457 (void) _rdrand32_step(&r);
458 * (uint32_t *) (void *)
459 &stream.key[crypto_stream_salsa20_KEYBYTES - 4] ^= (uint32_t) r;
460 #endif
461 /* LCOV_EXCL_STOP */
462 }
463
464 /*
465 * XOR the key with another same-length secret
466 */
467
468 static inline void
randombytes_salsa20_random_xorkey(const unsigned char * const mix)469 randombytes_salsa20_random_xorkey(const unsigned char * const mix)
470 {
471 unsigned char *key = stream.key;
472 size_t i;
473
474 for (i = (size_t) 0U; i < sizeof stream.key; i++) {
475 key[i] ^= mix[i];
476 }
477 }
478
479 /*
480 * Put `size` random bytes into `buf` and overwrite the key
481 */
482
483 static void
randombytes_salsa20_random_buf(void * const buf,const size_t size)484 randombytes_salsa20_random_buf(void * const buf, const size_t size)
485 {
486 size_t i;
487 int ret;
488
489 randombytes_salsa20_random_stir_if_needed();
490 COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
491 #if defined(ULONG_LONG_MAX) && defined(SIZE_MAX)
492 # if SIZE_MAX > ULONG_LONG_MAX
493 /* coverity[result_independent_of_operands] */
494 assert(size <= ULONG_LONG_MAX);
495 # endif
496 #endif
497 ret = crypto_stream_salsa20((unsigned char *) buf, (unsigned long long) size,
498 (unsigned char *) &stream.nonce, stream.key);
499 assert(ret == 0);
500 for (i = 0U; i < sizeof size; i++) {
501 stream.key[i] ^= ((const unsigned char *) (const void *) &size)[i];
502 }
503 randombytes_salsa20_random_xorhwrand();
504 stream.nonce++;
505 crypto_stream_salsa20_xor(stream.key, stream.key, sizeof stream.key,
506 (unsigned char *) &stream.nonce, stream.key);
507 }
508
509 /*
510 * Pop a 32-bit value from the random pool
511 *
512 * Overwrite the key after the pool gets refilled.
513 */
514
515 static uint32_t
randombytes_salsa20_random(void)516 randombytes_salsa20_random(void)
517 {
518 uint32_t val;
519 int ret;
520
521 COMPILER_ASSERT(sizeof stream.rnd32 >= (sizeof stream.key) + (sizeof val));
522 COMPILER_ASSERT(((sizeof stream.rnd32) - (sizeof stream.key))
523 % sizeof val == (size_t) 0U);
524 if (stream.rnd32_outleft <= (size_t) 0U) {
525 randombytes_salsa20_random_stir_if_needed();
526 COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
527 ret = crypto_stream_salsa20((unsigned char *) stream.rnd32,
528 (unsigned long long) sizeof stream.rnd32,
529 (unsigned char *) &stream.nonce,
530 stream.key);
531 assert(ret == 0);
532 stream.rnd32_outleft = (sizeof stream.rnd32) - (sizeof stream.key);
533 randombytes_salsa20_random_xorhwrand();
534 randombytes_salsa20_random_xorkey(&stream.rnd32[stream.rnd32_outleft]);
535 memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof stream.key);
536 stream.nonce++;
537 }
538 stream.rnd32_outleft -= sizeof val;
539 memcpy(&val, &stream.rnd32[stream.rnd32_outleft], sizeof val);
540 memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof val);
541
542 return val;
543 }
544
545 static const char *
randombytes_salsa20_implementation_name(void)546 randombytes_salsa20_implementation_name(void)
547 {
548 return "salsa20";
549 }
550
551 struct randombytes_implementation randombytes_salsa20_implementation = {
552 SODIUM_C99(.implementation_name =) randombytes_salsa20_implementation_name,
553 SODIUM_C99(.random =) randombytes_salsa20_random,
554 SODIUM_C99(.stir =) randombytes_salsa20_random_stir,
555 SODIUM_C99(.uniform =) NULL,
556 SODIUM_C99(.buf =) randombytes_salsa20_random_buf,
557 SODIUM_C99(.close =) randombytes_salsa20_random_close
558 };
559