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 unsigned char m0[crypto_stream_salsa20_KEYBYTES +
333 crypto_stream_salsa20_NONCEBYTES];
334
335 memset(stream.rnd32, 0, sizeof stream.rnd32);
336 stream.rnd32_outleft = (size_t) 0U;
337 if (global.initialized == 0) {
338 randombytes_salsa20_random_init();
339 global.initialized = 1;
340 }
341 #ifdef HAVE_GETPID
342 global.pid = getpid();
343 #endif
344
345 #ifndef _WIN32
346
347 # ifdef HAVE_SAFE_ARC4RANDOM
348 arc4random_buf(m0, sizeof m0);
349 # elif defined(SYS_getrandom) && defined(__NR_getrandom)
350 if (global.getrandom_available != 0) {
351 if (randombytes_linux_getrandom(m0, sizeof m0) != 0) {
352 sodium_misuse(); /* LCOV_EXCL_LINE */
353 }
354 } else if (global.random_data_source_fd == -1 ||
355 safe_read(global.random_data_source_fd, m0,
356 sizeof m0) != (ssize_t) sizeof m0) {
357 sodium_misuse(); /* LCOV_EXCL_LINE */
358 }
359 # else
360 if (global.random_data_source_fd == -1 ||
361 safe_read(global.random_data_source_fd, m0,
362 sizeof m0) != (ssize_t) sizeof m0) {
363 sodium_misuse(); /* LCOV_EXCL_LINE */
364 }
365 # endif
366
367 #else /* _WIN32 */
368 if (! RtlGenRandom((PVOID) m0, (ULONG) sizeof m0)) {
369 sodium_misuse(); /* LCOV_EXCL_LINE */
370 }
371 #endif
372
373 crypto_stream_salsa20(stream.key, sizeof stream.key,
374 m0 + crypto_stream_salsa20_KEYBYTES, m0);
375 sodium_memzero(m0, sizeof m0);
376 stream.initialized = 1;
377 }
378
379 /*
380 * Reseed the generator if it hasn't been initialized yet
381 */
382
383 static void
randombytes_salsa20_random_stir_if_needed(void)384 randombytes_salsa20_random_stir_if_needed(void)
385 {
386 #ifdef HAVE_GETPID
387 if (stream.initialized == 0) {
388 randombytes_salsa20_random_stir();
389 } else if (global.pid != getpid()) {
390 sodium_misuse(); /* LCOV_EXCL_LINE */
391 }
392 #else
393 if (stream.initialized == 0) {
394 randombytes_salsa20_random_stir();
395 }
396 #endif
397 }
398
399 /*
400 * Close the stream, free global resources
401 */
402
403 #ifdef _WIN32
404 static int
randombytes_salsa20_random_close(void)405 randombytes_salsa20_random_close(void)
406 {
407 int ret = -1;
408
409 if (global.initialized != 0) {
410 global.initialized = 0;
411 ret = 0;
412 }
413 sodium_memzero(&stream, sizeof stream);
414
415 return ret;
416 }
417 #else
418 static int
randombytes_salsa20_random_close(void)419 randombytes_salsa20_random_close(void)
420 {
421 int ret = -1;
422
423 if (global.random_data_source_fd != -1 &&
424 close(global.random_data_source_fd) == 0) {
425 global.random_data_source_fd = -1;
426 global.initialized = 0;
427 # ifdef HAVE_GETPID
428 global.pid = (pid_t) 0;
429 # endif
430 ret = 0;
431 }
432
433 # ifdef HAVE_SAFE_ARC4RANDOM
434 ret = 0;
435 # endif
436
437 # if defined(SYS_getrandom) && defined(__NR_getrandom)
438 if (global.getrandom_available != 0) {
439 ret = 0;
440 }
441 # endif
442
443 sodium_memzero(&stream, sizeof stream);
444
445 return ret;
446 }
447 #endif
448
449 /*
450 * RDRAND is only used to mitigate prediction if a key is compromised
451 */
452
453 static void
randombytes_salsa20_random_xorhwrand(void)454 randombytes_salsa20_random_xorhwrand(void)
455 {
456 /* LCOV_EXCL_START */
457 #ifdef HAVE_RDRAND
458 unsigned int r;
459
460 if (global.rdrand_available == 0) {
461 return;
462 }
463 (void) _rdrand32_step(&r);
464 * (uint32_t *) (void *)
465 &stream.key[crypto_stream_salsa20_KEYBYTES - 4] ^= (uint32_t) r;
466 #endif
467 /* LCOV_EXCL_STOP */
468 }
469
470 /*
471 * XOR the key with another same-length secret
472 */
473
474 static inline void
randombytes_salsa20_random_xorkey(const unsigned char * const mix)475 randombytes_salsa20_random_xorkey(const unsigned char * const mix)
476 {
477 unsigned char *key = stream.key;
478 size_t i;
479
480 for (i = (size_t) 0U; i < sizeof stream.key; i++) {
481 key[i] ^= mix[i];
482 }
483 }
484
485 /*
486 * Put `size` random bytes into `buf` and overwrite the key
487 */
488
489 static void
randombytes_salsa20_random_buf(void * const buf,const size_t size)490 randombytes_salsa20_random_buf(void * const buf, const size_t size)
491 {
492 size_t i;
493 int ret;
494
495 randombytes_salsa20_random_stir_if_needed();
496 COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
497 #if defined(ULONG_LONG_MAX) && defined(SIZE_MAX)
498 # if SIZE_MAX > ULONG_LONG_MAX
499 /* coverity[result_independent_of_operands] */
500 assert(size <= ULONG_LONG_MAX);
501 # endif
502 #endif
503 ret = crypto_stream_salsa20((unsigned char *) buf, (unsigned long long) size,
504 (unsigned char *) &stream.nonce, stream.key);
505 assert(ret == 0);
506 for (i = 0U; i < sizeof size; i++) {
507 stream.key[i] ^= ((const unsigned char *) (const void *) &size)[i];
508 }
509 randombytes_salsa20_random_xorhwrand();
510 stream.nonce++;
511 crypto_stream_salsa20_xor(stream.key, stream.key, sizeof stream.key,
512 (unsigned char *) &stream.nonce, stream.key);
513 }
514
515 /*
516 * Pop a 32-bit value from the random pool
517 *
518 * Overwrite the key after the pool gets refilled.
519 */
520
521 static uint32_t
randombytes_salsa20_random(void)522 randombytes_salsa20_random(void)
523 {
524 uint32_t val;
525 int ret;
526
527 COMPILER_ASSERT(sizeof stream.rnd32 >= (sizeof stream.key) + (sizeof val));
528 COMPILER_ASSERT(((sizeof stream.rnd32) - (sizeof stream.key))
529 % sizeof val == (size_t) 0U);
530 if (stream.rnd32_outleft <= (size_t) 0U) {
531 randombytes_salsa20_random_stir_if_needed();
532 COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
533 ret = crypto_stream_salsa20((unsigned char *) stream.rnd32,
534 (unsigned long long) sizeof stream.rnd32,
535 (unsigned char *) &stream.nonce,
536 stream.key);
537 assert(ret == 0);
538 stream.rnd32_outleft = (sizeof stream.rnd32) - (sizeof stream.key);
539 randombytes_salsa20_random_xorhwrand();
540 randombytes_salsa20_random_xorkey(&stream.rnd32[stream.rnd32_outleft]);
541 memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof stream.key);
542 stream.nonce++;
543 }
544 stream.rnd32_outleft -= sizeof val;
545 memcpy(&val, &stream.rnd32[stream.rnd32_outleft], sizeof val);
546 memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof val);
547
548 return val;
549 }
550
551 static const char *
randombytes_salsa20_implementation_name(void)552 randombytes_salsa20_implementation_name(void)
553 {
554 return "salsa20";
555 }
556
557 struct randombytes_implementation randombytes_salsa20_implementation = {
558 SODIUM_C99(.implementation_name =) randombytes_salsa20_implementation_name,
559 SODIUM_C99(.random =) randombytes_salsa20_random,
560 SODIUM_C99(.stir =) randombytes_salsa20_random_stir,
561 SODIUM_C99(.uniform =) NULL,
562 SODIUM_C99(.buf =) randombytes_salsa20_random_buf,
563 SODIUM_C99(.close =) randombytes_salsa20_random_close
564 };
565