1 /* $NetBSD: evutil_rand.c,v 1.2 2013/04/11 16:56:41 christos Exp $ */ 2 /* 3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* This file has our secure PRNG code. On platforms that have arc4random(), 29 * we just use that. Otherwise, we include arc4random.c as a bunch of static 30 * functions, and wrap it lightly. We don't expose the arc4random*() APIs 31 * because A) they aren't in our namespace, and B) it's not nice to name your 32 * APIs after their implementations. We keep them in a separate file 33 * so that other people can rip it out and use it for whatever. 34 */ 35 36 #include "event2/event-config.h" 37 #include <sys/cdefs.h> 38 __RCSID("$NetBSD: evutil_rand.c,v 1.2 2013/04/11 16:56:41 christos Exp $"); 39 40 #include <limits.h> 41 42 #include "util-internal.h" 43 #include "evthread-internal.h" 44 45 #ifdef _EVENT_HAVE_ARC4RANDOM 46 #include <stdlib.h> 47 #include <string.h> 48 int 49 evutil_secure_rng_init(void) 50 { 51 /* call arc4random() now to force it to self-initialize */ 52 (void) arc4random(); 53 return 0; 54 } 55 int 56 /*ARGSUSED*/ 57 evutil_secure_rng_global_setup_locks_(const int enable_locks) 58 { 59 return 0; 60 } 61 62 static void 63 /*ARGSUED*/ 64 ev_arc4random_buf(void *buf, size_t n) 65 { 66 #if defined(_EVENT_HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__) 67 arc4random_buf(buf, n); 68 return; 69 #else 70 unsigned char *b = buf; 71 72 #if defined(_EVENT_HAVE_ARC4RANDOM_BUF) 73 /* OSX 10.7 introducd arc4random_buf, so if you build your program 74 * there, you'll get surprised when older versions of OSX fail to run. 75 * To solve this, we can check whether the function pointer is set, 76 * and fall back otherwise. (OSX does this using some linker 77 * trickery.) 78 */ 79 if (arc4random_buf != NULL) { 80 return arc4random_buf(buf, n); 81 } 82 #endif 83 /* Make sure that we start out with b at a 4-byte alignment; plenty 84 * of CPUs care about this for 32-bit access. */ 85 if (n >= 4 && ((ev_uintptr_t)b) & 3) { 86 ev_uint32_t u = arc4random(); 87 int n_bytes = 4 - (((ev_uintptr_t)b) & 3); 88 memcpy(b, &u, n_bytes); 89 b += n_bytes; 90 n -= n_bytes; 91 } 92 while (n >= 4) { 93 *(ev_uint32_t*)b = arc4random(); 94 b += 4; 95 n -= 4; 96 } 97 if (n) { 98 ev_uint32_t u = arc4random(); 99 memcpy(b, &u, n); 100 } 101 #endif 102 } 103 104 #else /* !_EVENT_HAVE_ARC4RANDOM { */ 105 106 #ifdef _EVENT_ssize_t 107 #define ssize_t _EVENT_SSIZE_t 108 #endif 109 #define ARC4RANDOM_EXPORT static 110 #define _ARC4_LOCK() EVLOCK_LOCK(arc4rand_lock, 0) 111 #define _ARC4_UNLOCK() EVLOCK_UNLOCK(arc4rand_lock, 0) 112 #ifndef _EVENT_DISABLE_THREAD_SUPPORT 113 static void *arc4rand_lock; 114 #endif 115 116 #define ARC4RANDOM_UINT32 ev_uint32_t 117 #define ARC4RANDOM_NOSTIR 118 #define ARC4RANDOM_NORANDOM 119 #define ARC4RANDOM_NOUNIFORM 120 121 #include "./arc4random.c" 122 123 #ifndef _EVENT_DISABLE_THREAD_SUPPORT 124 int 125 evutil_secure_rng_global_setup_locks_(const int enable_locks) 126 { 127 EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0); 128 return 0; 129 } 130 #endif 131 132 int 133 evutil_secure_rng_init(void) 134 { 135 int val; 136 137 _ARC4_LOCK(); 138 if (!arc4_seeded_ok) 139 arc4_stir(); 140 val = arc4_seeded_ok ? 0 : -1; 141 _ARC4_UNLOCK(); 142 return val; 143 } 144 145 static void 146 ev_arc4random_buf(void *buf, size_t n) 147 { 148 arc4random_buf(buf, n); 149 } 150 151 #endif /* } !_EVENT_HAVE_ARC4RANDOM */ 152 153 void 154 evutil_secure_rng_get_bytes(void *buf, size_t n) 155 { 156 ev_arc4random_buf(buf, n); 157 } 158 159 void 160 evutil_secure_rng_add_bytes(const char *buf, size_t n) 161 { 162 arc4random_addrandom(__UNCONST(buf), 163 n>(size_t)INT_MAX ? INT_MAX : (int)n); 164 } 165 166