1 2 #include <assert.h> 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <limits.h> 6 #include <stdint.h> 7 #include <string.h> 8 #ifndef _WIN32 9 # include <unistd.h> 10 #endif 11 12 #include <stdlib.h> 13 #include <sys/types.h> 14 #ifndef _WIN32 15 # include <sys/stat.h> 16 # include <sys/time.h> 17 #endif 18 #ifdef __linux__ 19 # ifdef __dietlibc__ 20 # define _LINUX_SOURCE 21 # else 22 # include <sys/syscall.h> 23 # endif 24 # include <poll.h> 25 #endif 26 27 #include "core.h" 28 #include "private/common.h" 29 #include "randombytes.h" 30 #include "randombytes_sysrandom.h" 31 #include "utils.h" 32 33 #ifdef _WIN32 34 /* `RtlGenRandom` is used over `CryptGenRandom` on Microsoft Windows based systems: 35 * - `CryptGenRandom` requires pulling in `CryptoAPI` which causes unnecessary 36 * memory overhead if this API is not being used for other purposes 37 * - `RtlGenRandom` is thus called directly instead. A detailed explanation 38 * can be found here: https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/ 39 * 40 * In spite of the disclaimer on the `RtlGenRandom` documentation page that was 41 * written back in the Windows XP days, this function is here to stay. The CRT 42 * function `rand_s()` directly depends on it, so touching it would break many 43 * applications released since Windows XP. 44 * 45 * Also note that Rust, Firefox and BoringSSL (thus, Google Chrome and everything 46 * based on Chromium) also depend on it, and that libsodium allows the RNG to be 47 * replaced without patching nor recompiling the library. 48 */ 49 # include <windows.h> 50 # define RtlGenRandom SystemFunction036 51 # if defined(__cplusplus) 52 extern "C" 53 # endif 54 BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); 55 # pragma comment(lib, "advapi32.lib") 56 #endif 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 66 #ifdef HAVE_SAFE_ARC4RANDOM 67 68 static uint32_t 69 randombytes_sysrandom(void) 70 { 71 return arc4random(); 72 } 73 74 static void 75 randombytes_sysrandom_stir(void) 76 { 77 } 78 79 static void 80 randombytes_sysrandom_buf(void * const buf, const size_t size) 81 { 82 arc4random_buf(buf, size); 83 } 84 85 static int 86 randombytes_sysrandom_close(void) 87 { 88 return 0; 89 } 90 91 #else /* __OpenBSD__ */ 92 93 typedef struct SysRandom_ { 94 int random_data_source_fd; 95 int initialized; 96 int getrandom_available; 97 } SysRandom; 98 99 static SysRandom stream = { 100 SODIUM_C99(.random_data_source_fd =) -1, 101 SODIUM_C99(.initialized =) 0, 102 SODIUM_C99(.getrandom_available =) 0 103 }; 104 105 #ifndef _WIN32 106 static ssize_t 107 safe_read(const int fd, void * const buf_, size_t size) 108 { 109 unsigned char *buf = (unsigned char *) buf_; 110 ssize_t readnb; 111 112 assert(size > (size_t) 0U); 113 assert(size <= SSIZE_MAX); 114 do { 115 while ((readnb = read(fd, buf, size)) < (ssize_t) 0 && 116 (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */ 117 if (readnb < (ssize_t) 0) { 118 return readnb; /* LCOV_EXCL_LINE */ 119 } 120 if (readnb == (ssize_t) 0) { 121 break; /* LCOV_EXCL_LINE */ 122 } 123 size -= (size_t) readnb; 124 buf += readnb; 125 } while (size > (ssize_t) 0); 126 127 return (ssize_t) (buf - (unsigned char *) buf_); 128 } 129 #endif 130 131 #ifndef _WIN32 132 # if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL) 133 static int 134 randombytes_block_on_dev_random(void) 135 { 136 struct pollfd pfd; 137 int fd; 138 int pret; 139 140 fd = open("/dev/random", O_RDONLY); 141 if (fd == -1) { 142 return 0; 143 } 144 pfd.fd = fd; 145 pfd.events = POLLIN; 146 pfd.revents = 0; 147 do { 148 pret = poll(&pfd, 1, -1); 149 } while (pret < 0 && (errno == EINTR || errno == EAGAIN)); 150 if (pret != 1) { 151 (void) close(fd); 152 errno = EIO; 153 return -1; 154 } 155 return close(fd); 156 } 157 # endif 158 159 static int 160 randombytes_sysrandom_random_dev_open(void) 161 { 162 /* LCOV_EXCL_START */ 163 struct stat st; 164 static const char *devices[] = { 165 # ifndef USE_BLOCKING_RANDOM 166 "/dev/urandom", 167 # endif 168 "/dev/random", NULL 169 }; 170 const char **device = devices; 171 int fd; 172 173 # if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL) 174 if (randombytes_block_on_dev_random() != 0) { 175 return -1; 176 } 177 # endif 178 do { 179 fd = open(*device, O_RDONLY); 180 if (fd != -1) { 181 if (fstat(fd, &st) == 0 && 182 # ifdef __COMPCERT__ 183 1 184 # elif defined(S_ISNAM) 185 (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) 186 # else 187 S_ISCHR(st.st_mode) 188 # endif 189 ) { 190 # if defined(F_SETFD) && defined(FD_CLOEXEC) 191 (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 192 # endif 193 return fd; 194 } 195 (void) close(fd); 196 } else if (errno == EINTR) { 197 continue; 198 } 199 device++; 200 } while (*device != NULL); 201 202 errno = EIO; 203 return -1; 204 /* LCOV_EXCL_STOP */ 205 } 206 207 # if defined(__dietlibc__) || (defined(SYS_getrandom) && defined(__NR_getrandom)) 208 static int 209 _randombytes_linux_getrandom(void * const buf, const size_t size) 210 { 211 int readnb; 212 213 assert(size <= 256U); 214 do { 215 # ifdef __dietlibc__ 216 readnb = getrandom(buf, size, 0); 217 # else 218 readnb = syscall(SYS_getrandom, buf, (int) size, 0); 219 # endif 220 } while (readnb < 0 && (errno == EINTR || errno == EAGAIN)); 221 222 return (readnb == (int) size) - 1; 223 } 224 225 static int 226 randombytes_linux_getrandom(void * const buf_, size_t size) 227 { 228 unsigned char *buf = (unsigned char *) buf_; 229 size_t chunk_size = 256U; 230 231 do { 232 if (size < chunk_size) { 233 chunk_size = size; 234 assert(chunk_size > (size_t) 0U); 235 } 236 if (_randombytes_linux_getrandom(buf, chunk_size) != 0) { 237 return -1; 238 } 239 size -= chunk_size; 240 buf += chunk_size; 241 } while (size > (size_t) 0U); 242 243 return 0; 244 } 245 # endif 246 247 static void 248 randombytes_sysrandom_init(void) 249 { 250 const int errno_save = errno; 251 252 # if defined(SYS_getrandom) && defined(__NR_getrandom) 253 { 254 unsigned char fodder[16]; 255 256 if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) { 257 stream.getrandom_available = 1; 258 errno = errno_save; 259 return; 260 } 261 stream.getrandom_available = 0; 262 } 263 # endif 264 265 if ((stream.random_data_source_fd = 266 randombytes_sysrandom_random_dev_open()) == -1) { 267 sodium_misuse(); /* LCOV_EXCL_LINE */ 268 } 269 errno = errno_save; 270 } 271 272 #else /* _WIN32 */ 273 274 static void 275 randombytes_sysrandom_init(void) 276 { 277 } 278 #endif 279 280 static void 281 randombytes_sysrandom_stir(void) 282 { 283 if (stream.initialized == 0) { 284 randombytes_sysrandom_init(); 285 stream.initialized = 1; 286 } 287 } 288 289 static void 290 randombytes_sysrandom_stir_if_needed(void) 291 { 292 if (stream.initialized == 0) { 293 randombytes_sysrandom_stir(); 294 } 295 } 296 297 static int 298 randombytes_sysrandom_close(void) 299 { 300 int ret = -1; 301 302 #ifndef _WIN32 303 if (stream.random_data_source_fd != -1 && 304 close(stream.random_data_source_fd) == 0) { 305 stream.random_data_source_fd = -1; 306 stream.initialized = 0; 307 ret = 0; 308 } 309 # if defined(SYS_getrandom) && defined(__NR_getrandom) 310 if (stream.getrandom_available != 0) { 311 ret = 0; 312 } 313 # endif 314 #else /* _WIN32 */ 315 if (stream.initialized != 0) { 316 stream.initialized = 0; 317 ret = 0; 318 } 319 #endif 320 return ret; 321 } 322 323 static void 324 randombytes_sysrandom_buf(void * const buf, const size_t size) 325 { 326 randombytes_sysrandom_stir_if_needed(); 327 #if defined(ULONG_LONG_MAX) && defined(SIZE_MAX) 328 # if SIZE_MAX > ULONG_LONG_MAX 329 /* coverity[result_independent_of_operands] */ 330 assert(size <= ULONG_LONG_MAX); 331 # endif 332 #endif 333 #ifndef _WIN32 334 # if defined(SYS_getrandom) && defined(__NR_getrandom) 335 if (stream.getrandom_available != 0) { 336 if (randombytes_linux_getrandom(buf, size) != 0) { 337 sodium_misuse(); /* LCOV_EXCL_LINE */ 338 } 339 return; 340 } 341 # endif 342 if (stream.random_data_source_fd == -1 || 343 safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) { 344 sodium_misuse(); /* LCOV_EXCL_LINE */ 345 } 346 #else 347 COMPILER_ASSERT(randombytes_BYTES_MAX <= 0xffffffffUL); 348 if (size > (size_t) 0xffffffffUL) { 349 sodium_misuse(); /* LCOV_EXCL_LINE */ 350 } 351 if (! RtlGenRandom((PVOID) buf, (ULONG) size)) { 352 sodium_misuse(); /* LCOV_EXCL_LINE */ 353 } 354 #endif 355 } 356 357 static uint32_t 358 randombytes_sysrandom(void) 359 { 360 uint32_t r; 361 362 randombytes_sysrandom_buf(&r, sizeof r); 363 364 return r; 365 } 366 367 #endif /* __OpenBSD__ */ 368 369 static const char * 370 randombytes_sysrandom_implementation_name(void) 371 { 372 return "sysrandom"; 373 } 374 375 struct randombytes_implementation randombytes_sysrandom_implementation = { 376 SODIUM_C99(.implementation_name =) randombytes_sysrandom_implementation_name, 377 SODIUM_C99(.random =) randombytes_sysrandom, 378 SODIUM_C99(.stir =) randombytes_sysrandom_stir, 379 SODIUM_C99(.uniform =) NULL, 380 SODIUM_C99(.buf =) randombytes_sysrandom_buf, 381 SODIUM_C99(.close =) randombytes_sysrandom_close 382 }; 383