1 /* 2 * Crypto-quality random number functions 3 * 4 * Author: Harlan Stenn, 2014 5 * 6 * This file is Copyright (c) 2014 by Network Time Foundation. 7 * BSD terms apply: see the file COPYRIGHT in the distribution root for details. 8 */ 9 10 #include "config.h" 11 #include <sys/types.h> 12 #ifdef HAVE_UNISTD_H 13 # include <unistd.h> 14 #endif 15 #include <stdio.h> 16 17 #include <ntp_stdlib.h> 18 #include <ntp_random.h> 19 #include "safecast.h" 20 21 #ifdef USE_OPENSSL_CRYPTO_RAND 22 #include <openssl/err.h> 23 #include <openssl/rand.h> 24 25 int crypto_rand_init = 0; 26 #elif !defined(HAVE_ARC4RANDOM_BUF) 27 #include <event2/util.h> 28 #endif 29 30 int crypto_rand_ok = 0; 31 32 /* 33 * As of late 2014, here's how we plan to provide cryptographic-quality 34 * random numbers: 35 * 36 * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes(). 37 * - Otherwise, use arc4random(). 38 * 39 * Use of arc4random() can be forced using configure options 40 * --disable-openssl-random or --without-crypto. 41 * 42 * We can count on arc4random existing, thru the OS or thru libevent. 43 * The quality of arc4random depends on the implementor. 44 * 45 * RAND_poll() doesn't show up until XXX. If it's not present, we 46 * need to either provide our own or use arc4random(). 47 */ 48 49 /* 50 * ntp_crypto_srandom: 51 * 52 * Initialize the random number generator, if needed by the underlying 53 * crypto random number generation mechanism. 54 */ 55 56 void 57 ntp_crypto_srandom( 58 void 59 ) 60 { 61 #ifdef USE_OPENSSL_CRYPTO_RAND 62 if (!crypto_rand_init) { 63 if (RAND_poll()) 64 crypto_rand_ok = 1; 65 crypto_rand_init = 1; 66 } 67 #elif HAVE_ARC4RANDOM_BUF 68 /* 69 * arc4random_buf has no error return and needs no seeding nor reseeding. 70 */ 71 crypto_rand_ok = 1; 72 #else 73 /* 74 * Explicitly init libevent secure RNG to make sure it seeds. 75 * This is the only way we can tell if it can successfully get 76 * entropy from the system. 77 */ 78 if (!evutil_secure_rng_init()) 79 crypto_rand_ok = 1; 80 #endif 81 } 82 83 84 /* 85 * ntp_crypto_random_buf: Used by ntp-keygen 86 * 87 * Returns 0 on success, -1 on error. 88 */ 89 int 90 ntp_crypto_random_buf( 91 void *buf, 92 size_t nbytes 93 ) 94 { 95 if (!crypto_rand_ok) 96 return -1; 97 98 #if defined(USE_OPENSSL_CRYPTO_RAND) 99 if (1 != RAND_bytes(buf, size2int_chk(nbytes))) { 100 unsigned long err; 101 char *err_str; 102 103 err = ERR_get_error(); 104 err_str = ERR_error_string(err, NULL); 105 msyslog(LOG_ERR, "RAND_bytes failed: %s", err_str); 106 107 return -1; 108 } 109 #elif defined(HAVE_ARC4RANDOM_BUF) 110 arc4random_buf(buf, nbytes); 111 #else 112 evutil_secure_rng_get_bytes(buf, nbytes); 113 #endif 114 return 0; 115 } 116