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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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