1- /* $NetBSD: arc4random.c,v 1.10 2011 /02/04 22:07:07 christos Exp $ */
1+ /* $NetBSD: arc4random.c,v 1.11 2012 /02/27 04:25:12 tls Exp $ */
22/* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */
33
44/*
2727
2828#include <sys/cdefs.h>
2929#if defined(LIBC_SCCS ) && !defined(lint )
30- __RCSID ("$NetBSD: arc4random.c,v 1.10 2011 /02/04 22:07:07 christos Exp $" );
30+ __RCSID ("$NetBSD: arc4random.c,v 1.11 2012 /02/27 04:25:12 tls Exp $" );
3131#endif /* LIBC_SCCS and not lint */
3232
3333#include "namespace.h"
34+ #include "reentrant.h"
3435#include <fcntl.h>
3536#include <stdlib.h>
3637#include <unistd.h>
@@ -44,13 +45,15 @@ __weak_alias(arc4random,_arc4random)
4445#endif
4546
4647struct arc4_stream {
48+ mutex_t mtx ;
4749 uint8_t i ;
4850 uint8_t j ;
4951 uint8_t s [256 ];
5052};
5153
5254static int rs_initialized ;
53- static struct arc4_stream rs ;
55+ /* XXX lint explodes with an internal error if only mtx is initialized! */
56+ static struct arc4_stream rs = { .i = 0 , .mtx = MUTEX_INITIALIZER };
5457
5558static inline void arc4_init (struct arc4_stream * );
5659static inline void arc4_addrandom (struct arc4_stream * , u_char * , int );
@@ -89,40 +92,29 @@ arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
8992static void
9093arc4_stir (struct arc4_stream * as )
9194{
92- int fd ;
93- struct {
94- struct timeval tv ;
95- u_int rnd [(128 - sizeof (struct timeval )) / sizeof (u_int )];
96- } rdat ;
95+ int rdat [128 / sizeof (int )];
9796 int n ;
97+ int mib [2 ];
98+ unsigned int i ;
99+ size_t len ;
98100
99- gettimeofday (& rdat .tv , NULL );
100- fd = open ("/dev/urandom" , O_RDONLY );
101- if (fd != -1 ) {
102- read (fd , rdat .rnd , sizeof (rdat .rnd ));
103- close (fd );
104- }
105- #ifdef KERN_URND
106- else {
107- int mib [2 ];
108- u_int i ;
109- size_t len ;
110-
111- /* Device could not be opened, we might be chrooted, take
112- * randomness from sysctl. */
113-
114- mib [0 ] = CTL_KERN ;
115- mib [1 ] = KERN_URND ;
116-
117- for (i = 0 ; i < sizeof (rdat .rnd ) / sizeof (u_int ); i ++ ) {
118- len = sizeof (u_int );
119- if (sysctl (mib , 2 , & rdat .rnd [i ], & len , NULL , 0 ) == -1 )
120- break ;
121- }
101+ /*
102+ * This code once opened and read /dev/urandom on each
103+ * call. That causes repeated rekeying of the kernel stream
104+ * generator, which is very wasteful. Because of application
105+ * behavior, caching the fd doesn't really help. So we just
106+ * fill up the tank from sysctl, which is a tiny bit slower
107+ * for us but much friendlier to other entropy consumers.
108+ */
109+
110+ mib [0 ] = CTL_KERN ;
111+ mib [1 ] = KERN_URND ;
112+
113+ for (i = 0 ; i < sizeof (rdat ) / sizeof (int ); i ++ ) {
114+ len = sizeof (rdat [i ]);
115+ if (sysctl (mib , 2 , & rdat [i ], & len , NULL , 0 ) == -1 )
116+ abort ();
122117 }
123- #endif
124- /* fd < 0 or failed sysctl ? Ah, what the heck. We'll just take
125- * whatever was on the stack... */
126118
127119 arc4_addrandom (as , (void * ) & rdat , sizeof (rdat ));
128120
@@ -160,8 +152,8 @@ arc4_getword(struct arc4_stream *as)
160152 return val ;
161153}
162154
163- void
164- arc4random_stir (void )
155+ static inline void
156+ _arc4random_stir_unlocked (void )
165157{
166158 if (!rs_initialized ) {
167159 arc4_init (& rs );
@@ -171,23 +163,67 @@ arc4random_stir(void)
171163}
172164
173165void
174- arc4random_addrandom (u_char * dat , int datlen )
166+ arc4random_stir (void )
167+ {
168+ #ifdef _REENTRANT
169+ if (__isthreaded ) {
170+ mutex_lock (& rs .mtx );
171+ _arc4random_stir_unlocked ();
172+ mutex_unlock (& rs .mtx );
173+ return ;
174+ }
175+ #endif
176+ _arc4random_stir_unlocked ();
177+ }
178+
179+ static inline void
180+ _arc4random_addrandom_unlocked (u_char * dat , int datlen )
175181{
176182 if (!rs_initialized )
177- arc4random_stir ( );
183+ arc4_stir ( & rs );
178184 arc4_addrandom (& rs , dat , datlen );
179185}
180186
181- uint32_t
182- arc4random (void )
187+ void
188+ arc4random_addrandom (u_char * dat , int datlen )
189+ {
190+ #ifdef _REENTRANT
191+ if (__isthreaded ) {
192+ mutex_lock (& rs .mtx );
193+ _arc4random_addrandom_unlocked (dat , datlen );
194+ mutex_unlock (& rs .mtx );
195+ return ;
196+ }
197+ #endif
198+ _arc4random_addrandom_unlocked (dat , datlen );
199+ }
200+
201+ static inline uint32_t
202+ _arc4random_unlocked (void )
183203{
184204 if (!rs_initialized )
185- arc4random_stir ( );
205+ arc4_stir ( & rs );
186206 return arc4_getword (& rs );
187207}
188208
189- void
190- arc4random_buf (void * buf , size_t len )
209+ uint32_t
210+ arc4random (void )
211+ {
212+ uint32_t v ;
213+ #ifdef _REENTRANT
214+ if (__isthreaded ) {
215+ mutex_lock (& rs .mtx );
216+ v = _arc4random_unlocked ();
217+ mutex_unlock (& rs .mtx );
218+ return v ;
219+ }
220+ #endif
221+ v = _arc4random_unlocked ();
222+ return v ;
223+ }
224+
225+ static void
226+ _arc4random_buf_unlocked (void * buf , size_t len )
191227{
192228 uint8_t * bp = buf ;
193229 uint8_t * ep = bp + len ;
@@ -200,6 +236,20 @@ arc4random_buf(void *buf, size_t len)
200236 * bp ++ = arc4_getbyte (& rs );
201237}
202238
239+ void
240+ arc4random_buf (void * buf , size_t len )
241+ {
242+ #ifdef _REENTRANT
243+ if (__isthreaded ) {
244+ mutex_lock (& rs .mtx );
245+ _arc4random_buf_unlocked (buf , len );
246+ mutex_unlock (& rs .mtx );
247+ return ;
248+ } else
249+ #endif
250+ _arc4random_buf_unlocked (buf , len );
251+ }
252+
203253/*-
204254 * Written by Damien Miller.
205255 * With simplifications by Jinmei Tatuya.
@@ -216,8 +266,8 @@ arc4random_buf(void *buf, size_t len)
216266 * [2^32 % upper_bound, 2^32[ which maps back to
217267 * [0, upper_bound[ after reduction modulo upper_bound.
218268 */
219- uint32_t
220- arc4random_uniform (uint32_t upper_bound )
269+ static uint32_t
270+ _arc4random_uniform_unlocked (uint32_t upper_bound )
221271{
222272 uint32_t r , min ;
223273
@@ -243,7 +293,7 @@ arc4random_uniform(uint32_t upper_bound)
243293 * to re-roll (at all).
244294 */
245295 if (!rs_initialized )
246- arc4random_stir ( );
296+ arc4_stir ( & rs );
247297 if (arc4_getbyte (& rs ) & 1 )
248298 (void )arc4_getbyte (& rs );
249299 do
@@ -253,24 +303,18 @@ arc4random_uniform(uint32_t upper_bound)
253303 return r % upper_bound ;
254304}
255305
256-
257- #if 0
258- /*-------- Test code for i386 --------*/
259- #include <stdio.h>
260- #include <machine/pctr.h>
261- int
262- main (int argc , char * * argv )
306+ uint32_t
307+ arc4random_uniform (uint32_t upper_bound )
263308{
264- const int iter = 1000000 ;
265- int i ;
266- pctrval v ;
267-
268- v = rdtsc ();
269- for (i = 0 ; i < iter ; i ++ )
270- arc4random ();
271- v = rdtsc () - v ;
272- v /= iter ;
273-
274- printf ("%qd cycles\n" , v );
275- }
309+ uint32_t v ;
310+ #ifdef _REENTRANT
311+ if (__isthreaded ) {
312+ mutex_lock (& rs .mtx );
313+ v = _arc4random_uniform_unlocked (upper_bound );
314+ mutex_unlock (& rs .mtx );
315+ return v ;
316+ }
276317#endif
318+ v = _arc4random_uniform_unlocked (upper_bound );
319+ return v ;
320+ }
0 commit comments