]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/arc4random.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / arc4random.c
1 /* $Id: arc4random.c 26092 2008-09-19 15:13:52Z androsyn $ */
2 /* $$$: arc4random.c 2005/02/08 robert */
3 /* $NetBSD: arc4random.c,v 1.5.2.1 2004/03/26 22:52:50 jmc Exp $ */
4 /* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */
5
6 /*
7 * Arc4 random number generator for OpenBSD.
8 * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
9 *
10 * Modification and redistribution in source and binary forms is
11 * permitted provided that due credit is given to the author and the
12 * OpenBSD project by leaving this copyright notice intact.
13 */
14
15 /*
16 * This code is derived from section 17.1 of Applied Cryptography,
17 * second edition, which describes a stream cipher allegedly
18 * compatible with RSA Labs "RC4" cipher (the actual description of
19 * which is a trade secret). The same algorithm is used as a stream
20 * cipher called "arcfour" in Tatu Ylonen's ssh package.
21 *
22 * Here the stream cipher has been modified always to include the time
23 * when initializing the state. That makes it impossible to
24 * regenerate the same random sequence twice, so this can't be used
25 * for encryption, but will generate good random numbers.
26 *
27 * RC4 is a registered trademark of RSA Laboratories.
28 */
29
30
31 #include <libratbox_config.h>
32 #include <ratbox_lib.h>
33
34 #if !defined(HAVE_OPENSSL) && !defined(HAVE_GNUTLS) && !defined(HAVE_ARC4RANDOM)
35
36 #include "arc4random.h"
37
38 #ifdef HAVE_GETRUSAGE
39 #include <sys/resource.h>
40 #endif
41
42
43
44 struct arc4_stream
45 {
46 uint8_t i;
47 uint8_t j;
48 uint8_t s[256];
49 };
50
51
52 static int rs_initialized;
53 static struct arc4_stream rs;
54
55 static inline void arc4_init(struct arc4_stream *);
56 static inline void arc4_addrandom(struct arc4_stream *, uint8_t *, int);
57 static void arc4_stir(struct arc4_stream *);
58 static inline uint8_t arc4_getbyte(struct arc4_stream *);
59 static inline uint32_t arc4_getword(struct arc4_stream *);
60
61 static inline void
62 arc4_init(struct arc4_stream *as)
63 {
64 int n;
65
66 for(n = 0; n < 256; n++)
67 as->s[n] = n;
68 as->i = 0;
69 as->j = 0;
70 }
71
72 static inline void
73 arc4_addrandom(struct arc4_stream *as, uint8_t *dat, int datlen)
74 {
75 int n;
76 uint8_t si;
77
78 as->i--;
79 for(n = 0; n < 256; n++)
80 {
81 as->i = (as->i + 1);
82 si = as->s[as->i];
83 as->j = (as->j + si + dat[n % datlen]);
84 as->s[as->i] = as->s[as->j];
85 as->s[as->j] = si;
86 }
87 as->j = as->i;
88 }
89
90 static void
91 arc4_stir(struct arc4_stream *as)
92 {
93 struct timeval tv;
94 pid_t pid;
95 int n;
96 /* XXX this doesn't support egd sources or similiar */
97
98 pid = getpid();
99 arc4_addrandom(as, (void *)&pid, sizeof(pid));
100
101 rb_gettimeofday(&tv, NULL);
102 arc4_addrandom(as, (void *)&tv.tv_sec, sizeof(&tv.tv_sec));
103 arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec));
104 rb_gettimeofday(&tv, NULL);
105 arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec));
106
107 #if defined(HAVE_GETRUSAGE) && RUSAGE_SELF
108 {
109 struct rusage buf;
110 getrusage(RUSAGE_SELF, &buf);
111 arc4_addrandom(as, (void *)&buf, sizeof(buf));
112 memset(&buf, 0, sizeof(buf))}
113 #endif
114
115 #if !defined(_WIN32)
116 {
117 uint8_t rnd[128];
118 int fd;
119 fd = open("/dev/urandom", O_RDONLY);
120 if(fd != -1)
121 {
122 read(fd, rnd, sizeof(rnd));
123 close(fd);
124 arc4_addrandom(as, (void *)rnd, sizeof(rnd));
125 memset(&rnd, 0, sizeof(rnd));
126 }
127
128 }
129 #else
130 {
131 LARGE_INTEGER performanceCount;
132 if(QueryPerformanceCounter(&performanceCount))
133 {
134 arc4_addrandom(as, (void *)&performanceCount, sizeof(performanceCount));
135 }
136 HMODULE lib = LoadLibrary("ADVAPI32.DLL");
137 if(lib)
138 {
139 uint8_t rnd[128];
140 BOOLEAN(APIENTRY * pfn) (void *, ULONG) =
141 (BOOLEAN(APIENTRY *) (void *, ULONG))GetProcAddress(lib,
142 "SystemFunction036");
143 if(pfn)
144 {
145 if(pfn(rnd, sizeof(rnd)) == TRUE)
146 arc4_addrandom(as, (void *)rnd, sizeof(rnd));
147 memset(&rnd, 0, sizeof(rnd));
148 }
149 }
150 }
151 #endif
152
153
154 /*
155 * Throw away the first N words of output, as suggested in the
156 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
157 * by Fluher, Mantin, and Shamir.
158 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
159 * N = 256 in our case.
160 */
161 for(n = 0; n < 256 * 4; n++)
162 arc4_getbyte(as);
163 }
164
165 static inline uint8_t
166 arc4_getbyte(struct arc4_stream *as)
167 {
168 uint8_t si, sj;
169
170 as->i = (as->i + 1);
171 si = as->s[as->i];
172 as->j = (as->j + si);
173 sj = as->s[as->j];
174 as->s[as->i] = sj;
175 as->s[as->j] = si;
176 return (as->s[(si + sj) & 0xff]);
177 }
178
179 static inline uint32_t
180 arc4_getword(struct arc4_stream *as)
181 {
182 uint32_t val;
183 val = arc4_getbyte(as) << 24;
184 val |= arc4_getbyte(as) << 16;
185 val |= arc4_getbyte(as) << 8;
186 val |= arc4_getbyte(as);
187 return val;
188 }
189
190 void
191 arc4random_stir(void)
192 {
193 if(!rs_initialized)
194 {
195 arc4_init(&rs);
196 rs_initialized = 1;
197 }
198 arc4_stir(&rs);
199 }
200
201 void
202 arc4random_addrandom(uint8_t *dat, int datlen)
203 {
204 if(!rs_initialized)
205 arc4random_stir();
206 arc4_addrandom(&rs, dat, datlen);
207 }
208
209 uint32_t
210 arc4random(void)
211 {
212 if(!rs_initialized)
213 arc4random_stir();
214 return arc4_getword(&rs);
215 }
216
217 #endif