]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/arc4random.c
534d2237194a538bd9cb78f3503908d6208f8eb1
[irc/rqf/shadowircd.git] / libratbox / src / arc4random.c
1 /* $Id: arc4random.c 25705 2008-07-11 18:21:57Z 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 uint8_t i;
46 uint8_t j;
47 uint8_t s[256];
48 };
49
50
51 static int rs_initialized;
52 static struct arc4_stream rs;
53
54 static inline void arc4_init(struct arc4_stream *);
55 static inline void arc4_addrandom(struct arc4_stream *, uint8_t *, int);
56 static void arc4_stir(struct arc4_stream *);
57 static inline uint8_t arc4_getbyte(struct arc4_stream *);
58 static inline uint32_t arc4_getword(struct arc4_stream *);
59
60 static inline void
61 arc4_init(struct arc4_stream *as)
62 {
63 int n;
64
65 for (n = 0; n < 256; n++)
66 as->s[n] = n;
67 as->i = 0;
68 as->j = 0;
69 }
70
71 static inline void
72 arc4_addrandom(struct arc4_stream *as, uint8_t *dat, int datlen)
73 {
74 int n;
75 uint8_t si;
76
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;
84 }
85 as->j = as->i;
86 }
87
88 static void
89 arc4_stir(struct arc4_stream *as)
90 {
91 struct timeval tv;
92 pid_t pid;
93 int n;
94 /* XXX this doesn't support egd sources or similiar */
95
96 pid = getpid();
97 arc4_addrandom(as, (void *)&pid, sizeof(pid));
98
99 rb_gettimeofday(&tv, NULL);
100 arc4_addrandom(as, (void *)&tv.tv_sec, sizeof(&tv.tv_sec));
101 arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec));
102 rb_gettimeofday(&tv, NULL);
103 arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec));
104
105 #if defined(HAVE_GETRUSAGE) && RUSAGE_SELF
106 {
107 struct rusage buf;
108 getrusage(RUSAGE_SELF, &buf);
109 arc4_addrandom(as, (void *)&buf, sizeof(buf));
110 memset(&buf, 0, sizeof(buf))
111 }
112 #endif
113
114 #if !defined(WIN32)
115 {
116 uint8_t rnd[128];
117 int fd;
118 fd = open("/dev/urandom", O_RDONLY);
119 if (fd != -1)
120 {
121 read(fd, rnd, sizeof(rnd));
122 close(fd);
123 arc4_addrandom(as, (void *)rnd, sizeof(rnd));
124 }
125 }
126 #else
127 {
128 LARGE_INTEGER performanceCount;
129 if (QueryPerformanceCounter (&performanceCount))
130 {
131 arc4_addrandom(as, (void *)&performanceCount, sizeof(performanceCount));
132 }
133 }
134 #endif
135
136
137 /*
138 * Throw away the first N words of output, as suggested in the
139 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
140 * by Fluher, Mantin, and Shamir.
141 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
142 * N = 256 in our case.
143 */
144 for (n = 0; n < 256 * 4; n++)
145 arc4_getbyte(as);
146 }
147
148 static inline uint8_t
149 arc4_getbyte(struct arc4_stream *as)
150 {
151 uint8_t si, sj;
152
153 as->i = (as->i + 1);
154 si = as->s[as->i];
155 as->j = (as->j + si);
156 sj = as->s[as->j];
157 as->s[as->i] = sj;
158 as->s[as->j] = si;
159 return (as->s[(si + sj) & 0xff]);
160 }
161
162 static inline uint32_t
163 arc4_getword(struct arc4_stream *as)
164 {
165 uint32_t val;
166 val = arc4_getbyte(as) << 24;
167 val |= arc4_getbyte(as) << 16;
168 val |= arc4_getbyte(as) << 8;
169 val |= arc4_getbyte(as);
170 return val;
171 }
172
173 void
174 arc4random_stir(void)
175 {
176 if (!rs_initialized) {
177 arc4_init(&rs);
178 rs_initialized = 1;
179 }
180 arc4_stir(&rs);
181 }
182
183 void
184 arc4random_addrandom(uint8_t *dat, int datlen)
185 {
186 if (!rs_initialized)
187 arc4random_stir();
188 arc4_addrandom(&rs, dat, datlen);
189 }
190
191 uint32_t
192 arc4random(void)
193 {
194 if (!rs_initialized)
195 arc4random_stir();
196 return arc4_getword(&rs);
197 }
198
199 #endif
200