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 25int crypto_rand_init = 0; 26#elif !defined(HAVE_ARC4RANDOM_BUF) 27#include <event2/util.h> 28#endif 29 30int 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 56void 57ntp_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 */ 89int 90ntp_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