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