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