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