]>
Commit | Line | Data |
---|---|---|
3202e249 | 1 | /* $Id: arc4random.c 26092 2008-09-19 15:13:52Z androsyn $ */ |
a9fb3ed0 VY |
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 | ||
608e20b4 | 34 | #if !defined(HAVE_OPENSSL) && !defined(HAVE_GNUTLS) && !defined(HAVE_ARC4RANDOM) |
a9fb3ed0 VY |
35 | |
36 | #include "arc4random.h" | |
37 | ||
38 | #ifdef HAVE_GETRUSAGE | |
39 | #include <sys/resource.h> | |
40 | #endif | |
41 | ||
42 | ||
43 | ||
3202e249 VY |
44 | struct arc4_stream |
45 | { | |
a9fb3ed0 VY |
46 | uint8_t i; |
47 | uint8_t j; | |
48 | uint8_t s[256]; | |
49 | }; | |
50 | ||
51 | ||
3202e249 | 52 | static int rs_initialized; |
a9fb3ed0 VY |
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 | { | |
3202e249 | 64 | int n; |
a9fb3ed0 | 65 | |
3202e249 | 66 | for(n = 0; n < 256; n++) |
a9fb3ed0 VY |
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 | { | |
3202e249 | 75 | int n; |
a9fb3ed0 VY |
76 | uint8_t si; |
77 | ||
78 | as->i--; | |
3202e249 VY |
79 | for(n = 0; n < 256; n++) |
80 | { | |
a9fb3ed0 VY |
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; | |
030272f3 VY |
96 | #ifdef _WIN32 |
97 | HMODULE lib; | |
98 | #endif | |
a9fb3ed0 VY |
99 | /* XXX this doesn't support egd sources or similiar */ |
100 | ||
101 | pid = getpid(); | |
3202e249 | 102 | arc4_addrandom(as, (void *)&pid, sizeof(pid)); |
a9fb3ed0 VY |
103 | |
104 | rb_gettimeofday(&tv, NULL); | |
105 | arc4_addrandom(as, (void *)&tv.tv_sec, sizeof(&tv.tv_sec)); | |
106 | arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec)); | |
107 | rb_gettimeofday(&tv, NULL); | |
108 | arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec)); | |
3202e249 | 109 | |
a9fb3ed0 VY |
110 | #if defined(HAVE_GETRUSAGE) && RUSAGE_SELF |
111 | { | |
112 | struct rusage buf; | |
113 | getrusage(RUSAGE_SELF, &buf); | |
114 | arc4_addrandom(as, (void *)&buf, sizeof(buf)); | |
3202e249 VY |
115 | memset(&buf, 0, sizeof(buf))} |
116 | #endif | |
a9fb3ed0 | 117 | |
3202e249 | 118 | #if !defined(_WIN32) |
a9fb3ed0 VY |
119 | { |
120 | uint8_t rnd[128]; | |
121 | int fd; | |
122 | fd = open("/dev/urandom", O_RDONLY); | |
3202e249 | 123 | if(fd != -1) |
a9fb3ed0 VY |
124 | { |
125 | read(fd, rnd, sizeof(rnd)); | |
126 | close(fd); | |
127 | arc4_addrandom(as, (void *)rnd, sizeof(rnd)); | |
3202e249 | 128 | memset(&rnd, 0, sizeof(rnd)); |
a9fb3ed0 | 129 | } |
3202e249 | 130 | |
a9fb3ed0 VY |
131 | } |
132 | #else | |
133 | { | |
134 | LARGE_INTEGER performanceCount; | |
3202e249 | 135 | if(QueryPerformanceCounter(&performanceCount)) |
a9fb3ed0 VY |
136 | { |
137 | arc4_addrandom(as, (void *)&performanceCount, sizeof(performanceCount)); | |
138 | } | |
030272f3 | 139 | lib = LoadLibrary("ADVAPI32.DLL"); |
3202e249 VY |
140 | if(lib) |
141 | { | |
142 | uint8_t rnd[128]; | |
143 | BOOLEAN(APIENTRY * pfn) (void *, ULONG) = | |
144 | (BOOLEAN(APIENTRY *) (void *, ULONG))GetProcAddress(lib, | |
145 | "SystemFunction036"); | |
146 | if(pfn) | |
147 | { | |
148 | if(pfn(rnd, sizeof(rnd)) == TRUE) | |
149 | arc4_addrandom(as, (void *)rnd, sizeof(rnd)); | |
150 | memset(&rnd, 0, sizeof(rnd)); | |
151 | } | |
152 | } | |
a9fb3ed0 VY |
153 | } |
154 | #endif | |
155 | ||
156 | ||
157 | /* | |
158 | * Throw away the first N words of output, as suggested in the | |
159 | * paper "Weaknesses in the Key Scheduling Algorithm of RC4" | |
160 | * by Fluher, Mantin, and Shamir. | |
161 | * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps | |
162 | * N = 256 in our case. | |
163 | */ | |
3202e249 | 164 | for(n = 0; n < 256 * 4; n++) |
a9fb3ed0 VY |
165 | arc4_getbyte(as); |
166 | } | |
167 | ||
168 | static inline uint8_t | |
169 | arc4_getbyte(struct arc4_stream *as) | |
170 | { | |
171 | uint8_t si, sj; | |
172 | ||
173 | as->i = (as->i + 1); | |
174 | si = as->s[as->i]; | |
175 | as->j = (as->j + si); | |
176 | sj = as->s[as->j]; | |
177 | as->s[as->i] = sj; | |
178 | as->s[as->j] = si; | |
179 | return (as->s[(si + sj) & 0xff]); | |
180 | } | |
181 | ||
182 | static inline uint32_t | |
183 | arc4_getword(struct arc4_stream *as) | |
184 | { | |
185 | uint32_t val; | |
186 | val = arc4_getbyte(as) << 24; | |
187 | val |= arc4_getbyte(as) << 16; | |
188 | val |= arc4_getbyte(as) << 8; | |
189 | val |= arc4_getbyte(as); | |
190 | return val; | |
191 | } | |
192 | ||
193 | void | |
194 | arc4random_stir(void) | |
195 | { | |
3202e249 VY |
196 | if(!rs_initialized) |
197 | { | |
a9fb3ed0 VY |
198 | arc4_init(&rs); |
199 | rs_initialized = 1; | |
200 | } | |
201 | arc4_stir(&rs); | |
202 | } | |
203 | ||
204 | void | |
205 | arc4random_addrandom(uint8_t *dat, int datlen) | |
206 | { | |
3202e249 | 207 | if(!rs_initialized) |
a9fb3ed0 VY |
208 | arc4random_stir(); |
209 | arc4_addrandom(&rs, dat, datlen); | |
210 | } | |
211 | ||
212 | uint32_t | |
213 | arc4random(void) | |
214 | { | |
3202e249 | 215 | if(!rs_initialized) |
a9fb3ed0 VY |
216 | arc4random_stir(); |
217 | return arc4_getword(&rs); | |
218 | } | |
219 | ||
220 | #endif |