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) 46extern "C" 47# endif 48BOOLEAN 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 81typedef 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 91typedef 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 99static Salsa20RandomGlobal global = { 100 SODIUM_C99(.initialized =) 0, 101 SODIUM_C99(.random_data_source_fd =) -1 102}; 103 104static 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 115static uint64_t 116sodium_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 128static uint64_t 129sodium_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 146static void 147randombytes_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 156static ssize_t 157safe_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) 181static int 182randombytes_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 208static int 209randombytes_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)) 250static int 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 267static int 268randombytes_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 289static void 290randombytes_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 329static void 330randombytes_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 377static void 378randombytes_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 398static int 399randombytes_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 412static int 413randombytes_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 447static void 448randombytes_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 468static inline void 469randombytes_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 483static void 484randombytes_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 515static uint32_t 516randombytes_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 545static const char * 546randombytes_salsa20_implementation_name(void) 547{ 548 return "salsa20"; 549} 550 551struct 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