michael@0: /* michael@0: * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * 1. Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * 2. Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: * 3. The name of the author may not be used to endorse or promote products michael@0: * derived from this software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR michael@0: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES michael@0: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. michael@0: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, michael@0: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT michael@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF michael@0: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: /* This file has our secure PRNG code. On platforms that have arc4random(), michael@0: * we just use that. Otherwise, we include arc4random.c as a bunch of static michael@0: * functions, and wrap it lightly. We don't expose the arc4random*() APIs michael@0: * because A) they aren't in our namespace, and B) it's not nice to name your michael@0: * APIs after their implementations. We keep them in a separate file michael@0: * so that other people can rip it out and use it for whatever. michael@0: */ michael@0: michael@0: #include "event2/event-config.h" michael@0: michael@0: #include michael@0: michael@0: #include "util-internal.h" michael@0: #include "evthread-internal.h" michael@0: michael@0: #ifdef _EVENT_HAVE_ARC4RANDOM michael@0: #include michael@0: #include michael@0: int michael@0: evutil_secure_rng_init(void) michael@0: { michael@0: /* call arc4random() now to force it to self-initialize */ michael@0: (void) arc4random(); michael@0: return 0; michael@0: } michael@0: int michael@0: evutil_secure_rng_global_setup_locks_(const int enable_locks) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: static void michael@0: ev_arc4random_buf(void *buf, size_t n) michael@0: { michael@0: #if defined(_EVENT_HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__) michael@0: return arc4random_buf(buf, n); michael@0: #else michael@0: unsigned char *b = buf; michael@0: michael@0: /* Make sure that we start out with b at a 4-byte alignment; plenty michael@0: * of CPUs care about this for 32-bit access. */ michael@0: if (n >= 4 && ((ev_uintptr_t)b) & 3) { michael@0: ev_uint32_t u = arc4random(); michael@0: int n_bytes = 4 - (((ev_uintptr_t)b) & 3); michael@0: memcpy(b, &u, n_bytes); michael@0: b += n_bytes; michael@0: n -= n_bytes; michael@0: } michael@0: while (n >= 4) { michael@0: *(ev_uint32_t*)b = arc4random(); michael@0: b += 4; michael@0: n -= 4; michael@0: } michael@0: if (n) { michael@0: ev_uint32_t u = arc4random(); michael@0: memcpy(b, &u, n); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: #else /* !_EVENT_HAVE_ARC4RANDOM { */ michael@0: michael@0: #ifdef _EVENT_ssize_t michael@0: #define ssize_t _EVENT_SSIZE_t michael@0: #endif michael@0: #define ARC4RANDOM_EXPORT static michael@0: #define _ARC4_LOCK() EVLOCK_LOCK(arc4rand_lock, 0) michael@0: #define _ARC4_UNLOCK() EVLOCK_UNLOCK(arc4rand_lock, 0) michael@0: #ifndef _EVENT_DISABLE_THREAD_SUPPORT michael@0: static void *arc4rand_lock; michael@0: #endif michael@0: michael@0: #define ARC4RANDOM_UINT32 ev_uint32_t michael@0: #define ARC4RANDOM_NOSTIR michael@0: #define ARC4RANDOM_NORANDOM michael@0: #define ARC4RANDOM_NOUNIFORM michael@0: michael@0: #include "./arc4random.c" michael@0: michael@0: #ifndef _EVENT_DISABLE_THREAD_SUPPORT michael@0: int michael@0: evutil_secure_rng_global_setup_locks_(const int enable_locks) michael@0: { michael@0: EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0); michael@0: return 0; michael@0: } michael@0: #endif michael@0: michael@0: int michael@0: evutil_secure_rng_init(void) michael@0: { michael@0: int val; michael@0: michael@0: _ARC4_LOCK(); michael@0: if (!arc4_seeded_ok) michael@0: arc4_stir(); michael@0: val = arc4_seeded_ok ? 0 : -1; michael@0: _ARC4_UNLOCK(); michael@0: return val; michael@0: } michael@0: michael@0: static void michael@0: ev_arc4random_buf(void *buf, size_t n) michael@0: { michael@0: arc4random_buf(buf, n); michael@0: } michael@0: michael@0: #endif /* } !_EVENT_HAVE_ARC4RANDOM */ michael@0: michael@0: void michael@0: evutil_secure_rng_get_bytes(void *buf, size_t n) michael@0: { michael@0: ev_arc4random_buf(buf, n); michael@0: } michael@0: michael@0: #ifndef __OpenBSD__ michael@0: void michael@0: evutil_secure_rng_add_bytes(const char *buf, size_t n) michael@0: { michael@0: arc4random_addrandom((unsigned char*)buf, michael@0: n>(size_t)INT_MAX ? INT_MAX : (int)n); michael@0: } michael@0: #endif