]>
Commit | Line | Data |
---|---|---|
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 |