/* * Crypto-quality random number functions * * Author: Harlan Stenn, 2014 * * This file is Copyright (c) 2014 by Network Time Foundation. * BSD terms apply: see the file COPYRIGHT in the distribution root for details. */ #include "config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #include #include #include "safecast.h" #ifdef USE_OPENSSL_CRYPTO_RAND #include #include int crypto_rand_init = 0; #elif !defined(HAVE_ARC4RANDOM_BUF) #include #endif int crypto_rand_ok = 0; /* * As of late 2014, here's how we plan to provide cryptographic-quality * random numbers: * * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes(). * - Otherwise, use arc4random(). * * Use of arc4random() can be forced using configure options * --disable-openssl-random or --without-crypto. * * We can count on arc4random existing, thru the OS or thru libevent. * The quality of arc4random depends on the implementor. * * RAND_poll() doesn't show up until XXX. If it's not present, we * need to either provide our own or use arc4random(). */ /* * ntp_crypto_srandom: * * Initialize the random number generator, if needed by the underlying * crypto random number generation mechanism. */ void ntp_crypto_srandom( void ) { #ifdef USE_OPENSSL_CRYPTO_RAND if (!crypto_rand_init) { if (RAND_poll()) crypto_rand_ok = 1; crypto_rand_init = 1; } #elif HAVE_ARC4RANDOM_BUF /* * arc4random_buf has no error return and needs no seeding nor reseeding. */ crypto_rand_ok = 1; #else /* * Explicitly init libevent secure RNG to make sure it seeds. * This is the only way we can tell if it can successfully get * entropy from the system. */ if (!evutil_secure_rng_init()) crypto_rand_ok = 1; #endif } /* * ntp_crypto_random_buf: Used by ntp-keygen * * Returns 0 on success, -1 on error. */ int ntp_crypto_random_buf( void *buf, size_t nbytes ) { if (!crypto_rand_ok) return -1; #if defined(USE_OPENSSL_CRYPTO_RAND) if (1 != RAND_bytes(buf, size2int_chk(nbytes))) { unsigned long err; char *err_str; err = ERR_get_error(); err_str = ERR_error_string(err, NULL); msyslog(LOG_ERR, "RAND_bytes failed: %s", err_str); return -1; } #elif defined(HAVE_ARC4RANDOM_BUF) arc4random_buf(buf, nbytes); #else evutil_secure_rng_get_bytes(buf, nbytes); #endif return 0; }