arc4random.c revision 169981
1258945Sroberto/*
2258945Sroberto * Arc4 random number generator for OpenBSD.
3280849Scy * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
4258945Sroberto *
5258945Sroberto * Modification and redistribution in source and binary forms is
6258945Sroberto * permitted provided that due credit is given to the author and the
7280849Scy * OpenBSD project (for instance by leaving this copyright notice
8258945Sroberto * intact).
9258945Sroberto */
10258945Sroberto
11258945Sroberto/*
12258945Sroberto * This code is derived from section 17.1 of Applied Cryptography,
13258945Sroberto * second edition, which describes a stream cipher allegedly
14258945Sroberto * compatible with RSA Labs "RC4" cipher (the actual description of
15258945Sroberto * which is a trade secret).  The same algorithm is used as a stream
16258945Sroberto * cipher called "arcfour" in Tatu Ylonen's ssh package.
17258945Sroberto *
18280849Scy * Here the stream cipher has been modified always to include the time
19280849Scy * when initializing the state.  That makes it impossible to
20280849Scy * regenerate the same random sequence twice, so this can't be used
21280849Scy * for encryption, but will generate good random numbers.
22258945Sroberto *
23280849Scy * RC4 is a registered trademark of RSA Laboratories.
24280849Scy */
25258945Sroberto
26280849Scy#include <sys/cdefs.h>
27280849Scy__FBSDID("$FreeBSD: head/lib/libc/gen/arc4random.c 169981 2007-05-25 10:40:33Z delphij $");
28280849Scy
29280849Scy#include "namespace.h"
30280849Scy#include <sys/types.h>
31280849Scy#include <sys/time.h>
32258945Sroberto#include <stdlib.h>
33280849Scy#include <fcntl.h>
34258945Sroberto#include <unistd.h>
35280849Scy#include <pthread.h>
36258945Sroberto
37258945Sroberto#include "libc_private.h"
38280849Scy#include "un-namespace.h"
39258945Sroberto
40258945Srobertostruct arc4_stream {
41258945Sroberto	u_int8_t i;
42280849Scy	u_int8_t j;
43280849Scy	u_int8_t s[256];
44280849Scy};
45280849Scy
46258945Srobertostatic pthread_mutex_t	arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
47258945Sroberto
48258945Sroberto#define	RANDOMDEV	"/dev/urandom"
49258945Sroberto#define	THREAD_LOCK()						\
50258945Sroberto	do {							\
51258945Sroberto		if (__isthreaded)				\
52280849Scy			_pthread_mutex_lock(&arc4random_mtx);	\
53258945Sroberto	} while (0)
54280849Scy
55280849Scy#define	THREAD_UNLOCK()						\
56258945Sroberto	do {							\
57280849Scy		if (__isthreaded)				\
58280849Scy			_pthread_mutex_unlock(&arc4random_mtx);	\
59280849Scy	} while (0)
60258945Sroberto
61258945Srobertostatic struct arc4_stream rs;
62258945Srobertostatic int rs_initialized;
63258945Srobertostatic int rs_stired;
64258945Srobertostatic int arc4_count;
65280849Scy
66280849Scystatic inline u_int8_t arc4_getbyte(struct arc4_stream *);
67280849Scystatic void arc4_stir(struct arc4_stream *);
68280849Scy
69280849Scystatic inline void
70280849Scyarc4_init(struct arc4_stream *as)
71280849Scy{
72280849Scy	int     n;
73280849Scy
74280849Scy	for (n = 0; n < 256; n++)
75280849Scy		as->s[n] = n;
76258945Sroberto	as->i = 0;
77258945Sroberto	as->j = 0;
78280849Scy}
79280849Scy
80280849Scystatic inline void
81280849Scyarc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
82280849Scy{
83280849Scy	int     n;
84280849Scy	u_int8_t si;
85280849Scy
86258945Sroberto	as->i--;
87280849Scy	for (n = 0; n < 256; n++) {
88258945Sroberto		as->i = (as->i + 1);
89258945Sroberto		si = as->s[as->i];
90280849Scy		as->j = (as->j + si + dat[n % datlen]);
91280849Scy		as->s[as->i] = as->s[as->j];
92280849Scy		as->s[as->j] = si;
93280849Scy	}
94280849Scy}
95280849Scy
96258945Srobertostatic void
97258945Srobertoarc4_stir(struct arc4_stream *as)
98258945Sroberto{
99280849Scy	int     fd, n;
100258945Sroberto	struct {
101258945Sroberto		struct timeval tv;
102258945Sroberto		pid_t pid;
103280849Scy		u_int8_t rnd[128 - sizeof(struct timeval) - sizeof(pid_t)];
104258945Sroberto	}       rdat;
105258945Sroberto
106280849Scy	gettimeofday(&rdat.tv, NULL);
107280849Scy	rdat.pid = getpid();
108280849Scy	fd = _open(RANDOMDEV, O_RDONLY, 0);
109280849Scy	if (fd >= 0) {
110280849Scy		(void) _read(fd, rdat.rnd, sizeof(rdat.rnd));
111280849Scy		_close(fd);
112280849Scy	}
113280849Scy	/* fd < 0?  Ah, what the heck. We'll just take whatever was on the
114280849Scy	 * stack... */
115280849Scy
116290000Sglebius	arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
117280849Scy
118280849Scy	/*
119280849Scy	 * Throw away the first N bytes of output, as suggested in the
120258945Sroberto	 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
121258945Sroberto	 * by Fluher, Mantin, and Shamir.  N=1024 is based on
122258945Sroberto	 * suggestions in the paper "(Not So) Random Shuffles of RC4"
123258945Sroberto	 * by Ilya Mironov.
124258945Sroberto	 */
125258945Sroberto	for (n = 0; n < 1024; n++)
126258945Sroberto		(void) arc4_getbyte(as);
127258945Sroberto	arc4_count = 400000;
128258945Sroberto}
129258945Sroberto
130258945Srobertostatic inline u_int8_t
131258945Srobertoarc4_getbyte(struct arc4_stream *as)
132280849Scy{
133280849Scy	u_int8_t si, sj;
134280849Scy
135280849Scy	as->i = (as->i + 1);
136258945Sroberto	si = as->s[as->i];
137258945Sroberto	as->j = (as->j + si);
138280849Scy	sj = as->s[as->j];
139293894Sglebius	as->s[as->i] = sj;
140280849Scy	as->s[as->j] = si;
141280849Scy
142280849Scy	return (as->s[(si + sj) & 0xff]);
143280849Scy}
144280849Scy
145280849Scystatic inline u_int32_t
146258945Srobertoarc4_getword(struct arc4_stream *as)
147280849Scy{
148280849Scy	u_int32_t val;
149258945Sroberto
150280849Scy	val = arc4_getbyte(as) << 24;
151280849Scy	val |= arc4_getbyte(as) << 16;
152280849Scy	val |= arc4_getbyte(as) << 8;
153280849Scy	val |= arc4_getbyte(as);
154280849Scy
155280849Scy	return (val);
156280849Scy}
157280849Scy
158258945Srobertostatic void
159258945Srobertoarc4_check_init(void)
160280849Scy{
161280849Scy	if (!rs_initialized) {
162280849Scy		arc4_init(&rs);
163280849Scy		rs_initialized = 1;
164280849Scy	}
165280849Scy}
166280849Scy
167280849Scystatic void
168280849Scyarc4_check_stir(void)
169280849Scy{
170280849Scy	if (!rs_stired || --arc4_count == 0) {
171280849Scy		arc4_stir(&rs);
172280849Scy		rs_stired = 1;
173280849Scy	}
174280849Scy}
175258945Sroberto
176258945Srobertovoid
177258945Srobertoarc4random_stir(void)
178258945Sroberto{
179258945Sroberto	THREAD_LOCK();
180280849Scy	arc4_check_init();
181280849Scy	arc4_stir(&rs);
182280849Scy	THREAD_UNLOCK();
183280849Scy}
184280849Scy
185280849Scyvoid
186280849Scyarc4random_addrandom(u_char *dat, int datlen)
187294904Sdelphij{
188280849Scy	THREAD_LOCK();
189280849Scy	arc4_check_init();
190258945Sroberto	arc4_check_stir();
191258945Sroberto	arc4_addrandom(&rs, dat, datlen);
192258945Sroberto	THREAD_UNLOCK();
193280849Scy}
194280849Scy
195280849Scyu_int32_t
196258945Srobertoarc4random(void)
197280849Scy{
198258945Sroberto	u_int32_t rnd;
199280849Scy
200280849Scy	THREAD_LOCK();
201280849Scy	arc4_check_init();
202280849Scy	arc4_check_stir();
203280849Scy	rnd = arc4_getword(&rs);
204280849Scy	THREAD_UNLOCK();
205280849Scy
206280849Scy	return (rnd);
207280849Scy}
208258945Sroberto
209280849Scy#if 0
210280849Scy/*-------- Test code for i386 --------*/
211280849Scy#include <stdio.h>
212280849Scy#include <machine/pctr.h>
213280849Scyint
214280849Scymain(int argc, char **argv)
215280849Scy{
216280849Scy	const int iter = 1000000;
217280849Scy	int     i;
218280849Scy	pctrval v;
219258945Sroberto
220280849Scy	v = rdtsc();
221258945Sroberto	for (i = 0; i < iter; i++)
222258945Sroberto		arc4random();
223258945Sroberto	v = rdtsc() - v;
224280849Scy	v /= iter;
225280849Scy
226280849Scy	printf("%qd cycles\n", v);
227258945Sroberto}
228258945Sroberto#endif
229258945Sroberto