8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / crypt_modules / bsdbf / arc4random.c
blobc9cc3cb23920c51a8628b33ace2fc81b24346b5d
1 /*
2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 #pragma ident "%Z%%M% %I% %E% SMI"
8 /* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */
11 * Arc4 random number generator for OpenBSD.
12 * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
14 * Modification and redistribution in source and binary forms is
15 * permitted provided that due credit is given to the author and the
16 * OpenBSD project by leaving this copyright notice intact.
20 * This code is derived from section 17.1 of Applied Cryptography,
21 * second edition, which describes a stream cipher allegedly
22 * compatible with RSA Labs "RC4" cipher (the actual description of
23 * which is a trade secret). The same algorithm is used as a stream
24 * cipher called "arcfour" in Tatu Ylonen's ssh package.
26 * Here the stream cipher has been modified always to include the time
27 * when initializing the state. That makes it impossible to
28 * regenerate the same random sequence twice, so this can't be used
29 * for encryption, but will generate good random numbers.
31 * RC4 is a registered trademark of RSA Laboratories.
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/time.h>
41 #ifdef __GNUC__
42 #define inline __inline
43 #else /* !__GNUC__ */
44 #define inline
45 #endif /* !__GNUC__ */
47 struct arc4_stream {
48 uint8_t i;
49 uint8_t j;
50 uint8_t s[256];
53 int rs_initialized;
54 static struct arc4_stream rs;
56 static inline void
57 arc4_init(as)
58 struct arc4_stream *as;
60 int n;
62 for (n = 0; n < 256; n++)
63 as->s[n] = n;
64 as->i = 0;
65 as->j = 0;
68 static inline void
69 arc4_addrandom(as, dat, datlen)
70 struct arc4_stream *as;
71 u_char *dat;
72 size_t datlen;
74 int n;
75 uint8_t si;
77 as->i--;
78 for (n = 0; n < 256; n++) {
79 as->i = (as->i + 1);
80 si = as->s[as->i];
81 as->j = (as->j + si + dat[n % datlen]);
82 as->s[as->i] = as->s[as->j];
83 as->s[as->j] = si;
85 as->j = as->i;
88 static void
89 arc4_stir(as)
90 struct arc4_stream *as;
92 int fd;
93 struct {
94 struct timeval tv;
95 uint rnd[(128 - sizeof(struct timeval)) / sizeof(uint)];
96 } rdat;
98 (void) gettimeofday(&rdat.tv, NULL);
99 fd = open("/dev/urandom", O_RDONLY);
100 if (fd != -1) {
101 (void) read(fd, rdat.rnd, sizeof(rdat.rnd));
102 (void) close(fd);
104 /* fd < 0 ? Ah, what the heck. We'll just take
105 * whatever was on the stack... */
107 arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
110 static inline uint8_t
111 arc4_getbyte(as)
112 struct arc4_stream *as;
114 uint8_t si, sj;
116 as->i = (as->i + 1);
117 si = as->s[as->i];
118 as->j = (as->j + si);
119 sj = as->s[as->j];
120 as->s[as->i] = sj;
121 as->s[as->j] = si;
122 return (as->s[(si + sj) & 0xff]);
125 static inline uint32_t
126 arc4_getword(as)
127 struct arc4_stream *as;
129 uint32_t val;
130 val = arc4_getbyte(as) << 24;
131 val |= arc4_getbyte(as) << 16;
132 val |= arc4_getbyte(as) << 8;
133 val |= arc4_getbyte(as);
134 return val;
137 void
138 arc4random_stir()
140 if (!rs_initialized) {
141 arc4_init(&rs);
142 rs_initialized = 1;
144 arc4_stir(&rs);
147 void
148 arc4random_addrandom(dat, datlen)
149 u_char *dat;
150 size_t datlen;
152 if (!rs_initialized)
153 arc4random_stir();
154 arc4_addrandom(&rs, dat, datlen);
157 uint32_t
158 arc4random()
160 if (!rs_initialized)
161 arc4random_stir();
162 return arc4_getword(&rs);
165 #if 0
166 /*-------- Test code for i386 --------*/
167 #include <stdio.h>
168 #include <machine/pctr.h>
170 main(int argc, char **argv)
172 const int iter = 1000000;
173 int i;
174 pctrval v;
176 v = rdtsc();
177 for (i = 0; i < iter; i++)
178 arc4random();
179 v = rdtsc() - v;
180 v /= iter;
182 printf("%qd cycles\n", v);
184 #endif