1*eabc0478Schristos /* $NetBSD: evutil_rand.c,v 1.6 2024/08/18 20:47:21 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 58585484eSchristos * 68585484eSchristos * Redistribution and use in source and binary forms, with or without 78585484eSchristos * modification, are permitted provided that the following conditions 88585484eSchristos * are met: 98585484eSchristos * 1. Redistributions of source code must retain the above copyright 108585484eSchristos * notice, this list of conditions and the following disclaimer. 118585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 128585484eSchristos * notice, this list of conditions and the following disclaimer in the 138585484eSchristos * documentation and/or other materials provided with the distribution. 148585484eSchristos * 3. The name of the author may not be used to endorse or promote products 158585484eSchristos * derived from this software without specific prior written permission. 168585484eSchristos * 178585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 188585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 198585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 208585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 218585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 228585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 238585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 248585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 268585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278585484eSchristos */ 288585484eSchristos 298585484eSchristos /* This file has our secure PRNG code. On platforms that have arc4random(), 308585484eSchristos * we just use that. Otherwise, we include arc4random.c as a bunch of static 318585484eSchristos * functions, and wrap it lightly. We don't expose the arc4random*() APIs 328585484eSchristos * because A) they aren't in our namespace, and B) it's not nice to name your 338585484eSchristos * APIs after their implementations. We keep them in a separate file 348585484eSchristos * so that other people can rip it out and use it for whatever. 358585484eSchristos */ 368585484eSchristos 378585484eSchristos #include "event2/event-config.h" 388585484eSchristos #include "evconfig-private.h" 398585484eSchristos 408585484eSchristos #include <limits.h> 418585484eSchristos 428585484eSchristos #include "util-internal.h" 438585484eSchristos #include "evthread-internal.h" 448585484eSchristos 458585484eSchristos #ifdef EVENT__HAVE_ARC4RANDOM 468585484eSchristos #include <stdlib.h> 478585484eSchristos #include <string.h> 488585484eSchristos int 49b8ecfcfeSchristos evutil_secure_rng_set_urandom_device_file(char *fname) 50b8ecfcfeSchristos { 51b8ecfcfeSchristos (void) fname; 52b8ecfcfeSchristos return -1; 53b8ecfcfeSchristos } 54b8ecfcfeSchristos int 558585484eSchristos evutil_secure_rng_init(void) 568585484eSchristos { 578585484eSchristos /* call arc4random() now to force it to self-initialize */ 588585484eSchristos (void) arc4random(); 598585484eSchristos return 0; 608585484eSchristos } 618585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT 628585484eSchristos int 638585484eSchristos evutil_secure_rng_global_setup_locks_(const int enable_locks) 648585484eSchristos { 658585484eSchristos return 0; 668585484eSchristos } 678585484eSchristos #endif 688585484eSchristos static void 698585484eSchristos evutil_free_secure_rng_globals_locks(void) 708585484eSchristos { 718585484eSchristos } 728585484eSchristos 738585484eSchristos static void 748585484eSchristos ev_arc4random_buf(void *buf, size_t n) 758585484eSchristos { 768585484eSchristos #if defined(EVENT__HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__) 77b8ecfcfeSchristos arc4random_buf(buf, n); 78b8ecfcfeSchristos return; 798585484eSchristos #else 808585484eSchristos unsigned char *b = buf; 818585484eSchristos 828585484eSchristos #if defined(EVENT__HAVE_ARC4RANDOM_BUF) 838585484eSchristos /* OSX 10.7 introducd arc4random_buf, so if you build your program 848585484eSchristos * there, you'll get surprised when older versions of OSX fail to run. 858585484eSchristos * To solve this, we can check whether the function pointer is set, 868585484eSchristos * and fall back otherwise. (OSX does this using some linker 878585484eSchristos * trickery.) 888585484eSchristos */ 89b8ecfcfeSchristos { 90b8ecfcfeSchristos void (*tptr)(void *,size_t) = 91b8ecfcfeSchristos (void (*)(void*,size_t))arc4random_buf; 92b8ecfcfeSchristos if (tptr != NULL) { 93b8ecfcfeSchristos arc4random_buf(buf, n); 94b8ecfcfeSchristos return; 95b8ecfcfeSchristos } 968585484eSchristos } 978585484eSchristos #endif 988585484eSchristos /* Make sure that we start out with b at a 4-byte alignment; plenty 998585484eSchristos * of CPUs care about this for 32-bit access. */ 1008585484eSchristos if (n >= 4 && ((ev_uintptr_t)b) & 3) { 1018585484eSchristos ev_uint32_t u = arc4random(); 1028585484eSchristos int n_bytes = 4 - (((ev_uintptr_t)b) & 3); 1038585484eSchristos memcpy(b, &u, n_bytes); 1048585484eSchristos b += n_bytes; 1058585484eSchristos n -= n_bytes; 1068585484eSchristos } 1078585484eSchristos while (n >= 4) { 1088585484eSchristos *(ev_uint32_t*)b = arc4random(); 1098585484eSchristos b += 4; 1108585484eSchristos n -= 4; 1118585484eSchristos } 1128585484eSchristos if (n) { 1138585484eSchristos ev_uint32_t u = arc4random(); 1148585484eSchristos memcpy(b, &u, n); 1158585484eSchristos } 1168585484eSchristos #endif 1178585484eSchristos } 1188585484eSchristos 1198585484eSchristos #else /* !EVENT__HAVE_ARC4RANDOM { */ 1208585484eSchristos 1218585484eSchristos #ifdef EVENT__ssize_t 1228585484eSchristos #define ssize_t EVENT__ssize_t 1238585484eSchristos #endif 1248585484eSchristos #define ARC4RANDOM_EXPORT static 1258585484eSchristos #define ARC4_LOCK_() EVLOCK_LOCK(arc4rand_lock, 0) 1268585484eSchristos #define ARC4_UNLOCK_() EVLOCK_UNLOCK(arc4rand_lock, 0) 1278585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT 1288585484eSchristos static void *arc4rand_lock; 1298585484eSchristos #endif 1308585484eSchristos 1318585484eSchristos #define ARC4RANDOM_UINT32 ev_uint32_t 1328585484eSchristos #define ARC4RANDOM_NOSTIR 1338585484eSchristos #define ARC4RANDOM_NORANDOM 1348585484eSchristos #define ARC4RANDOM_NOUNIFORM 1358585484eSchristos 1368585484eSchristos #include "./arc4random.c" 1378585484eSchristos 1388585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT 1398585484eSchristos int 1408585484eSchristos evutil_secure_rng_global_setup_locks_(const int enable_locks) 1418585484eSchristos { 1428585484eSchristos EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0); 1438585484eSchristos return 0; 1448585484eSchristos } 1458585484eSchristos #endif 1468585484eSchristos 1478585484eSchristos static void 1488585484eSchristos evutil_free_secure_rng_globals_locks(void) 1498585484eSchristos { 1508585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT 1518585484eSchristos if (arc4rand_lock != NULL) { 1528585484eSchristos EVTHREAD_FREE_LOCK(arc4rand_lock, 0); 1538585484eSchristos arc4rand_lock = NULL; 1548585484eSchristos } 1558585484eSchristos #endif 1568585484eSchristos return; 1578585484eSchristos } 1588585484eSchristos 1598585484eSchristos int 160b8ecfcfeSchristos evutil_secure_rng_set_urandom_device_file(char *fname) 161b8ecfcfeSchristos { 162b8ecfcfeSchristos #ifdef TRY_SEED_URANDOM 163b8ecfcfeSchristos ARC4_LOCK_(); 164b8ecfcfeSchristos arc4random_urandom_filename = fname; 165b8ecfcfeSchristos ARC4_UNLOCK_(); 166b8ecfcfeSchristos #endif 167b8ecfcfeSchristos return 0; 168b8ecfcfeSchristos } 169b8ecfcfeSchristos 170b8ecfcfeSchristos int 1718585484eSchristos evutil_secure_rng_init(void) 1728585484eSchristos { 1738585484eSchristos int val; 1748585484eSchristos 1758585484eSchristos ARC4_LOCK_(); 176*eabc0478Schristos val = (!arc4_stir()) ? 0 : -1; 1778585484eSchristos ARC4_UNLOCK_(); 1788585484eSchristos return val; 1798585484eSchristos } 1808585484eSchristos 1818585484eSchristos static void 1828585484eSchristos ev_arc4random_buf(void *buf, size_t n) 1838585484eSchristos { 1848585484eSchristos arc4random_buf(buf, n); 1858585484eSchristos } 1868585484eSchristos 1878585484eSchristos #endif /* } !EVENT__HAVE_ARC4RANDOM */ 1888585484eSchristos 1898585484eSchristos void 1908585484eSchristos evutil_secure_rng_get_bytes(void *buf, size_t n) 1918585484eSchristos { 1928585484eSchristos ev_arc4random_buf(buf, n); 1938585484eSchristos } 1948585484eSchristos 195*eabc0478Schristos #if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM) 1968585484eSchristos void 1978585484eSchristos evutil_secure_rng_add_bytes(const char *buf, size_t n) 1988585484eSchristos { 1998585484eSchristos arc4random_addrandom((unsigned char*)buf, 2008585484eSchristos n>(size_t)INT_MAX ? INT_MAX : (int)n); 2018585484eSchristos } 202*eabc0478Schristos #endif 2038585484eSchristos 2048585484eSchristos void 2058585484eSchristos evutil_free_secure_rng_globals_(void) 2068585484eSchristos { 2078585484eSchristos evutil_free_secure_rng_globals_locks(); 2088585484eSchristos } 209