Lines 1-8
Link Here
|
1 |
/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ |
1 |
/* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */ |
2 |
|
2 |
|
3 |
/* |
3 |
/* |
4 |
* Copyright (c) 1996, David Mazieres <dm@uun.org> |
4 |
* Copyright (c) 1996, David Mazieres <dm@uun.org> |
5 |
* Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
5 |
* Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
|
|
6 |
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org> |
7 |
* Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> |
6 |
* |
8 |
* |
7 |
* Permission to use, copy, modify, and distribute this software for any |
9 |
* Permission to use, copy, modify, and distribute this software for any |
8 |
* purpose with or without fee is hereby granted, provided that the above |
10 |
* purpose with or without fee is hereby granted, provided that the above |
Lines 18-32
Link Here
|
18 |
*/ |
20 |
*/ |
19 |
|
21 |
|
20 |
/* |
22 |
/* |
21 |
* Arc4 random number generator for OpenBSD. |
23 |
* ChaCha based random number generator for OpenBSD. |
22 |
* |
|
|
23 |
* This code is derived from section 17.1 of Applied Cryptography, |
24 |
* second edition, which describes a stream cipher allegedly |
25 |
* compatible with RSA Labs "RC4" cipher (the actual description of |
26 |
* which is a trade secret). The same algorithm is used as a stream |
27 |
* cipher called "arcfour" in Tatu Ylonen's ssh package. |
28 |
* |
29 |
* RC4 is a registered trademark of RSA Laboratories. |
30 |
*/ |
24 |
*/ |
31 |
|
25 |
|
32 |
#include <sys/cdefs.h> |
26 |
#include <sys/cdefs.h> |
Lines 35-301
__FBSDID("$FreeBSD$");
Link Here
|
35 |
#include "namespace.h" |
29 |
#include "namespace.h" |
36 |
#include <fcntl.h> |
30 |
#include <fcntl.h> |
37 |
#include <limits.h> |
31 |
#include <limits.h> |
|
|
32 |
#include <pthread.h> |
33 |
#include <signal.h> |
34 |
#include <stdint.h> |
38 |
#include <stdlib.h> |
35 |
#include <stdlib.h> |
|
|
36 |
#include <string.h> |
39 |
#include <unistd.h> |
37 |
#include <unistd.h> |
40 |
#include <sys/param.h> |
38 |
#include <sys/types.h> |
41 |
#include <sys/sysctl.h> |
|
|
42 |
#include <sys/time.h> |
39 |
#include <sys/time.h> |
43 |
#include <pthread.h> |
40 |
|
44 |
|
|
|
45 |
#include "libc_private.h" |
41 |
#include "libc_private.h" |
46 |
#include "un-namespace.h" |
42 |
#include "un-namespace.h" |
47 |
|
43 |
|
48 |
#ifdef __GNUC__ |
44 |
#define KEYSTREAM_ONLY |
|
|
45 |
#include "chacha_private.h" |
46 |
|
47 |
#define minimum(a, b) ((a) < (b) ? (a) : (b)) |
48 |
|
49 |
#if defined(__GNUC__) || defined(_MSC_VER) |
49 |
#define inline __inline |
50 |
#define inline __inline |
50 |
#else /* !__GNUC__ */ |
51 |
#else /* __GNUC__ || _MSC_VER */ |
51 |
#define inline |
52 |
#define inline |
52 |
#endif /* !__GNUC__ */ |
53 |
#endif /* !__GNUC__ && !_MSC_VER */ |
53 |
|
54 |
|
54 |
struct arc4_stream { |
55 |
#define KEYSZ 32 |
55 |
u_int8_t i; |
56 |
#define IVSZ 8 |
56 |
u_int8_t j; |
57 |
#define BLOCKSZ 64 |
57 |
u_int8_t s[256]; |
58 |
#define RSBUFSZ (16*BLOCKSZ) |
58 |
}; |
|
|
59 |
|
59 |
|
60 |
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; |
60 |
/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ |
|
|
61 |
static struct _rs { |
62 |
size_t rs_have; /* valid bytes at end of rs_buf */ |
63 |
size_t rs_count; /* bytes till reseed */ |
64 |
} *rs; |
61 |
|
65 |
|
62 |
#define KEYSIZE 128 |
66 |
/* Maybe be preserved in fork children, if _rs_allocate() decides. */ |
63 |
#define _ARC4_LOCK() \ |
67 |
static struct _rsx { |
64 |
do { \ |
68 |
chacha_ctx rs_chacha; /* chacha context for random keystream */ |
65 |
if (__isthreaded) \ |
69 |
u_char rs_buf[RSBUFSZ]; /* keystream blocks */ |
66 |
_pthread_mutex_lock(&arc4random_mtx); \ |
70 |
} *rsx; |
67 |
} while (0) |
|
|
68 |
|
71 |
|
69 |
#define _ARC4_UNLOCK() \ |
72 |
static inline int _rs_allocate(struct _rs **, struct _rsx **); |
70 |
do { \ |
73 |
static inline void _rs_forkdetect(void); |
71 |
if (__isthreaded) \ |
74 |
#include "arc4random.h" |
72 |
_pthread_mutex_unlock(&arc4random_mtx); \ |
|
|
73 |
} while (0) |
74 |
|
75 |
|
75 |
static int rs_initialized; |
76 |
static inline void _rs_rekey(u_char *dat, size_t datlen); |
76 |
static struct arc4_stream rs; |
|
|
77 |
static pid_t arc4_stir_pid; |
78 |
static int arc4_count; |
79 |
|
77 |
|
80 |
extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, |
|
|
81 |
void *newp, size_t newlen); |
82 |
|
83 |
static inline u_int8_t arc4_getbyte(void); |
84 |
static void arc4_stir(void); |
85 |
|
86 |
static inline void |
78 |
static inline void |
87 |
arc4_init(void) |
79 |
_rs_init(u_char *buf, size_t n) |
88 |
{ |
80 |
{ |
89 |
int n; |
81 |
if (n < KEYSZ + IVSZ) |
|
|
82 |
return; |
90 |
|
83 |
|
91 |
for (n = 0; n < 256; n++) |
84 |
if (rs == NULL) { |
92 |
rs.s[n] = n; |
85 |
if (_rs_allocate(&rs, &rsx) == -1) |
93 |
rs.i = 0; |
86 |
abort(); |
94 |
rs.j = 0; |
87 |
} |
|
|
88 |
|
89 |
chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); |
90 |
chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); |
95 |
} |
91 |
} |
96 |
|
92 |
|
97 |
static inline void |
93 |
static void |
98 |
arc4_addrandom(u_char *dat, int datlen) |
94 |
_rs_stir(void) |
99 |
{ |
95 |
{ |
100 |
int n; |
96 |
u_char rnd[KEYSZ + IVSZ]; |
101 |
u_int8_t si; |
|
|
102 |
|
97 |
|
103 |
rs.i--; |
98 |
if (getentropy(rnd, sizeof rnd) == -1) |
104 |
for (n = 0; n < 256; n++) { |
99 |
_getentropy_fail(); |
105 |
rs.i = (rs.i + 1); |
|
|
106 |
si = rs.s[rs.i]; |
107 |
rs.j = (rs.j + si + dat[n % datlen]); |
108 |
rs.s[rs.i] = rs.s[rs.j]; |
109 |
rs.s[rs.j] = si; |
110 |
} |
111 |
rs.j = rs.i; |
112 |
} |
113 |
|
100 |
|
114 |
size_t |
101 |
if (!rs) |
115 |
__arc4_sysctl(u_char *buf, size_t size) |
102 |
_rs_init(rnd, sizeof(rnd)); |
116 |
{ |
103 |
else |
117 |
int mib[2]; |
104 |
_rs_rekey(rnd, sizeof(rnd)); |
118 |
size_t len, done; |
105 |
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ |
119 |
|
106 |
|
120 |
mib[0] = CTL_KERN; |
107 |
/* invalidate rs_buf */ |
121 |
mib[1] = KERN_ARND; |
108 |
rs->rs_have = 0; |
122 |
done = 0; |
109 |
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); |
123 |
|
110 |
|
124 |
do { |
111 |
rs->rs_count = 1600000; |
125 |
len = size; |
|
|
126 |
if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) |
127 |
return (done); |
128 |
done += len; |
129 |
buf += len; |
130 |
size -= len; |
131 |
} while (size > 0); |
132 |
|
133 |
return (done); |
134 |
} |
112 |
} |
135 |
|
113 |
|
136 |
static void |
114 |
static inline void |
137 |
arc4_stir(void) |
115 |
_rs_stir_if_needed(size_t len) |
138 |
{ |
116 |
{ |
139 |
u_char rdat[KEYSIZE]; |
117 |
_rs_forkdetect(); |
140 |
int i; |
118 |
if (!rs || rs->rs_count <= len) |
141 |
|
119 |
_rs_stir(); |
142 |
if (!rs_initialized) { |
120 |
if (rs->rs_count <= len) |
143 |
arc4_init(); |
121 |
rs->rs_count = 0; |
144 |
rs_initialized = 1; |
122 |
else |
145 |
} |
123 |
rs->rs_count -= len; |
146 |
if (__arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) { |
|
|
147 |
/* |
148 |
* The sysctl cannot fail. If it does fail on some FreeBSD |
149 |
* derivative or after some future change, just abort so that |
150 |
* the problem will be found and fixed. abort is not normally |
151 |
* suitable for a library but makes sense here. |
152 |
*/ |
153 |
abort(); |
154 |
} |
155 |
|
156 |
arc4_addrandom(rdat, KEYSIZE); |
157 |
|
158 |
/* |
159 |
* Discard early keystream, as per recommendations in: |
160 |
* "(Not So) Random Shuffles of RC4" by Ilya Mironov. |
161 |
*/ |
162 |
for (i = 0; i < 3072; i++) |
163 |
(void)arc4_getbyte(); |
164 |
arc4_count = 1600000; |
165 |
} |
124 |
} |
166 |
|
125 |
|
167 |
static void |
126 |
static inline void |
168 |
arc4_stir_if_needed(void) |
127 |
_rs_rekey(u_char *dat, size_t datlen) |
169 |
{ |
128 |
{ |
170 |
pid_t pid = getpid(); |
129 |
#ifndef KEYSTREAM_ONLY |
|
|
130 |
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); |
131 |
#endif |
132 |
/* fill rs_buf with the keystream */ |
133 |
chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, |
134 |
rsx->rs_buf, sizeof(rsx->rs_buf)); |
135 |
/* mix in optional user provided data */ |
136 |
if (dat) { |
137 |
size_t i, m; |
171 |
|
138 |
|
172 |
if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { |
139 |
m = minimum(datlen, KEYSZ + IVSZ); |
173 |
arc4_stir_pid = pid; |
140 |
for (i = 0; i < m; i++) |
174 |
arc4_stir(); |
141 |
rsx->rs_buf[i] ^= dat[i]; |
175 |
} |
142 |
} |
|
|
143 |
/* immediately reinit for backtracking resistance */ |
144 |
_rs_init(rsx->rs_buf, KEYSZ + IVSZ); |
145 |
memset(rsx->rs_buf, 0, KEYSZ + IVSZ); |
146 |
rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; |
176 |
} |
147 |
} |
177 |
|
148 |
|
178 |
static inline u_int8_t |
149 |
static inline void |
179 |
arc4_getbyte(void) |
150 |
_rs_random_buf(void *_buf, size_t n) |
180 |
{ |
151 |
{ |
181 |
u_int8_t si, sj; |
152 |
u_char *buf = (u_char *)_buf; |
|
|
153 |
u_char *keystream; |
154 |
size_t m; |
182 |
|
155 |
|
183 |
rs.i = (rs.i + 1); |
156 |
_rs_stir_if_needed(n); |
184 |
si = rs.s[rs.i]; |
157 |
while (n > 0) { |
185 |
rs.j = (rs.j + si); |
158 |
if (rs->rs_have > 0) { |
186 |
sj = rs.s[rs.j]; |
159 |
m = minimum(n, rs->rs_have); |
187 |
rs.s[rs.i] = sj; |
160 |
keystream = rsx->rs_buf + sizeof(rsx->rs_buf) |
188 |
rs.s[rs.j] = si; |
161 |
- rs->rs_have; |
189 |
return (rs.s[(si + sj) & 0xff]); |
162 |
memcpy(buf, keystream, m); |
|
|
163 |
memset(keystream, 0, m); |
164 |
buf += m; |
165 |
n -= m; |
166 |
rs->rs_have -= m; |
167 |
} |
168 |
if (rs->rs_have == 0) |
169 |
_rs_rekey(NULL, 0); |
170 |
} |
190 |
} |
171 |
} |
191 |
|
172 |
|
192 |
static inline u_int32_t |
173 |
static inline void |
193 |
arc4_getword(void) |
174 |
_rs_random_u32(uint32_t *val) |
194 |
{ |
175 |
{ |
195 |
u_int32_t val; |
176 |
u_char *keystream; |
196 |
val = arc4_getbyte() << 24; |
|
|
197 |
val |= arc4_getbyte() << 16; |
198 |
val |= arc4_getbyte() << 8; |
199 |
val |= arc4_getbyte(); |
200 |
return val; |
201 |
} |
202 |
|
177 |
|
203 |
void |
178 |
_rs_stir_if_needed(sizeof(*val)); |
204 |
arc4random_stir(void) |
179 |
if (rs->rs_have < sizeof(*val)) |
205 |
{ |
180 |
_rs_rekey(NULL, 0); |
206 |
_ARC4_LOCK(); |
181 |
keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; |
207 |
arc4_stir(); |
182 |
memcpy(val, keystream, sizeof(*val)); |
208 |
_ARC4_UNLOCK(); |
183 |
memset(keystream, 0, sizeof(*val)); |
|
|
184 |
rs->rs_have -= sizeof(*val); |
209 |
} |
185 |
} |
210 |
|
186 |
|
211 |
void |
187 |
uint32_t |
212 |
arc4random_addrandom(u_char *dat, int datlen) |
188 |
arc4random(void) |
213 |
{ |
189 |
{ |
214 |
_ARC4_LOCK(); |
190 |
uint32_t val; |
215 |
if (!rs_initialized) |
|
|
216 |
arc4_stir(); |
217 |
arc4_addrandom(dat, datlen); |
218 |
_ARC4_UNLOCK(); |
219 |
} |
220 |
|
191 |
|
221 |
u_int32_t |
|
|
222 |
arc4random(void) |
223 |
{ |
224 |
u_int32_t val; |
225 |
_ARC4_LOCK(); |
192 |
_ARC4_LOCK(); |
226 |
arc4_count -= 4; |
193 |
_rs_random_u32(&val); |
227 |
arc4_stir_if_needed(); |
|
|
228 |
val = arc4_getword(); |
229 |
_ARC4_UNLOCK(); |
194 |
_ARC4_UNLOCK(); |
230 |
return val; |
195 |
return val; |
231 |
} |
196 |
} |
232 |
|
197 |
|
233 |
void |
198 |
void |
234 |
arc4random_buf(void *_buf, size_t n) |
199 |
arc4random_buf(void *buf, size_t n) |
235 |
{ |
200 |
{ |
236 |
u_char *buf = (u_char *)_buf; |
|
|
237 |
_ARC4_LOCK(); |
201 |
_ARC4_LOCK(); |
238 |
arc4_stir_if_needed(); |
202 |
_rs_random_buf(buf, n); |
239 |
while (n--) { |
|
|
240 |
if (--arc4_count <= 0) |
241 |
arc4_stir(); |
242 |
buf[n] = arc4_getbyte(); |
243 |
} |
244 |
_ARC4_UNLOCK(); |
203 |
_ARC4_UNLOCK(); |
245 |
} |
204 |
} |
246 |
|
|
|
247 |
/* |
248 |
* Calculate a uniformly distributed random number less than upper_bound |
249 |
* avoiding "modulo bias". |
250 |
* |
251 |
* Uniformity is achieved by generating new random numbers until the one |
252 |
* returned is outside the range [0, 2**32 % upper_bound). This |
253 |
* guarantees the selected random number will be inside |
254 |
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) |
255 |
* after reduction modulo upper_bound. |
256 |
*/ |
257 |
u_int32_t |
258 |
arc4random_uniform(u_int32_t upper_bound) |
259 |
{ |
260 |
u_int32_t r, min; |
261 |
|
262 |
if (upper_bound < 2) |
263 |
return 0; |
264 |
|
265 |
/* 2**32 % x == (2**32 - x) % x */ |
266 |
min = -upper_bound % upper_bound; |
267 |
/* |
268 |
* This could theoretically loop forever but each retry has |
269 |
* p > 0.5 (worst case, usually far better) of selecting a |
270 |
* number inside the range we need, so it should rarely need |
271 |
* to re-roll. |
272 |
*/ |
273 |
for (;;) { |
274 |
r = arc4random(); |
275 |
if (r >= min) |
276 |
break; |
277 |
} |
278 |
|
279 |
return r % upper_bound; |
280 |
} |
281 |
|
282 |
#if 0 |
283 |
/*-------- Test code for i386 --------*/ |
284 |
#include <stdio.h> |
285 |
#include <machine/pctr.h> |
286 |
int |
287 |
main(int argc, char **argv) |
288 |
{ |
289 |
const int iter = 1000000; |
290 |
int i; |
291 |
pctrval v; |
292 |
|
293 |
v = rdtsc(); |
294 |
for (i = 0; i < iter; i++) |
295 |
arc4random(); |
296 |
v = rdtsc() - v; |
297 |
v /= iter; |
298 |
|
299 |
printf("%qd cycles\n", v); |
300 |
} |
301 |
#endif |