Lines 3-8
Link Here
|
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> |
6 |
* |
7 |
* |
7 |
* Permission to use, copy, modify, and distribute this software for any |
8 |
* Permission to use, copy, modify, and distribute this software for any |
8 |
* purpose with or without fee is hereby granted, provided that the above |
9 |
* purpose with or without fee is hereby granted, provided that the above |
Lines 18-32
Link Here
|
18 |
*/ |
19 |
*/ |
19 |
|
20 |
|
20 |
/* |
21 |
/* |
21 |
* Arc4 random number generator for OpenBSD. |
22 |
* 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 |
*/ |
23 |
*/ |
31 |
|
24 |
|
32 |
#include <sys/cdefs.h> |
25 |
#include <sys/cdefs.h> |
Lines 37-67
__FBSDID("$FreeBSD$");
Link Here
|
37 |
#include <limits.h> |
30 |
#include <limits.h> |
38 |
#include <stdlib.h> |
31 |
#include <stdlib.h> |
39 |
#include <unistd.h> |
32 |
#include <unistd.h> |
|
|
33 |
#include <string.h> |
40 |
#include <sys/types.h> |
34 |
#include <sys/types.h> |
41 |
#include <sys/param.h> |
35 |
#include <sys/param.h> |
42 |
#include <sys/sysctl.h> |
36 |
#include <sys/sysctl.h> |
43 |
#include <sys/time.h> |
37 |
#include <sys/time.h> |
|
|
38 |
#include <sys/mman.h> |
44 |
#include <pthread.h> |
39 |
#include <pthread.h> |
45 |
|
40 |
|
46 |
#include "libc_private.h" |
41 |
#include "libc_private.h" |
47 |
#include "un-namespace.h" |
42 |
#include "un-namespace.h" |
48 |
|
43 |
|
|
|
44 |
#define KEYSTREAM_ONLY |
45 |
#include "chacha_private.h" |
46 |
|
49 |
#ifdef __GNUC__ |
47 |
#ifdef __GNUC__ |
50 |
#define inline __inline |
48 |
#define inline __inline |
51 |
#else /* !__GNUC__ */ |
49 |
#else /* !__GNUC__ */ |
52 |
#define inline |
50 |
#define inline |
53 |
#endif /* !__GNUC__ */ |
51 |
#endif /* !__GNUC__ */ |
54 |
|
52 |
|
55 |
struct arc4_stream { |
|
|
56 |
u_int8_t i; |
57 |
u_int8_t j; |
58 |
u_int8_t s[256]; |
59 |
}; |
60 |
|
61 |
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; |
53 |
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; |
62 |
|
54 |
|
63 |
#define RANDOMDEV "/dev/random" |
55 |
#define RANDOMDEV "/dev/random" |
64 |
#define KEYSIZE 128 |
56 |
#define KEYSZ 32 |
|
|
57 |
#define IVSZ 8 |
58 |
#define BLOCKSZ 64 |
59 |
#define RSBUFSZ (16 * BLOCKSZ) |
65 |
#define _ARC4_LOCK() \ |
60 |
#define _ARC4_LOCK() \ |
66 |
do { \ |
61 |
do { \ |
67 |
if (__isthreaded) \ |
62 |
if (__isthreaded) \ |
Lines 74-120
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
Link Here
|
74 |
_pthread_mutex_unlock(&arc4random_mtx); \ |
69 |
_pthread_mutex_unlock(&arc4random_mtx); \ |
75 |
} while (0) |
70 |
} while (0) |
76 |
|
71 |
|
77 |
static int rs_initialized; |
72 |
/* Marked INHERIT_ZERO, so zero'd out in fork children. */ |
78 |
static struct arc4_stream rs; |
73 |
static struct { |
79 |
static pid_t arc4_stir_pid; |
74 |
/* valid bytes at end of rs_buf */ |
80 |
static int arc4_count; |
75 |
size_t rs_have; |
|
|
76 |
/* bytes till reseed */ |
77 |
size_t rs_count; |
78 |
} *rs; |
79 |
|
80 |
/* Preserved in fork children */ |
81 |
static struct { |
82 |
/* chacha context for random keystream */ |
83 |
chacha_ctx ctx; |
84 |
/* keystream blocks */ |
85 |
u_char rs_buf[RSBUFSZ]; |
86 |
} *rsx; |
81 |
|
87 |
|
82 |
extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, |
88 |
extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, |
83 |
void *newp, size_t newlen); |
89 |
void *newp, size_t newlen); |
84 |
|
90 |
|
85 |
static inline u_int8_t arc4_getbyte(void); |
91 |
static inline void _rs_rekey(u_char *dat, size_t datlen); |
86 |
static void arc4_stir(void); |
|
|
87 |
|
92 |
|
88 |
static inline void |
93 |
static inline void |
89 |
arc4_init(void) |
94 |
_rs_init(u_char *buf, size_t n) |
90 |
{ |
95 |
{ |
91 |
int n; |
96 |
if (n < (KEYSZ+ IVSZ)) |
|
|
97 |
return; |
92 |
|
98 |
|
93 |
for (n = 0; n < 256; n++) |
99 |
if (rs == NULL) { |
94 |
rs.s[n] = n; |
100 |
if ((rs = mmap(NULL, sizeof(*rs), PROT_READ|PROT_WRITE, |
95 |
rs.i = 0; |
101 |
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) |
96 |
rs.j = 0; |
102 |
abort(); |
97 |
} |
|
|
98 |
|
103 |
|
99 |
static inline void |
104 |
if (minherit(rs, sizeof(*rs), INHERIT_ZERO) == -1) { |
100 |
arc4_addrandom(u_char *dat, int datlen) |
105 |
munmap(rs, sizeof(*rs)); |
101 |
{ |
106 |
abort(); |
102 |
int n; |
107 |
} |
103 |
u_int8_t si; |
108 |
|
104 |
|
109 |
if ((rsx = mmap(NULL, sizeof(*rsx), PROT_READ|PROT_WRITE, |
105 |
rs.i--; |
110 |
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { |
106 |
for (n = 0; n < 256; n++) { |
111 |
munmap(rs, sizeof(*rs)); |
107 |
rs.i = (rs.i + 1); |
112 |
abort(); |
108 |
si = rs.s[rs.i]; |
113 |
} |
109 |
rs.j = (rs.j + si + dat[n % datlen]); |
114 |
|
110 |
rs.s[rs.i] = rs.s[rs.j]; |
115 |
if (minherit(rsx, sizeof(*rsx), INHERIT_ZERO) == -1) { |
111 |
rs.s[rs.j] = si; |
116 |
munmap(rsx, sizeof(*rsx)); |
|
|
117 |
munmap(rs, sizeof(*rs)); |
118 |
abort(); |
119 |
} |
112 |
} |
120 |
} |
113 |
rs.j = rs.i; |
121 |
|
|
|
122 |
chacha_keysetup(&rsx->ctx, buf, KEYSZ * 8, 0); |
123 |
chacha_ivsetup(&rsx->ctx, buf + KEYSZ); |
114 |
} |
124 |
} |
115 |
|
125 |
|
116 |
static size_t |
126 |
static size_t |
117 |
arc4_sysctl(u_char *buf, size_t size) |
127 |
_rs_sysctl(u_char *buf, size_t size) |
118 |
{ |
128 |
{ |
119 |
int mib[2]; |
129 |
int mib[2]; |
120 |
size_t len, done; |
130 |
size_t len, done; |
Lines 135-233
arc4_sysctl(u_char *buf, size_t size)
Link Here
|
135 |
return (done); |
145 |
return (done); |
136 |
} |
146 |
} |
137 |
|
147 |
|
|
|
148 |
static size_t |
149 |
arc4_sysctl(u_char *buf, size_t size) |
150 |
{ |
151 |
return (_rs_sysctl(buf, size)); |
152 |
} |
153 |
|
138 |
static void |
154 |
static void |
139 |
arc4_stir(void) |
155 |
_rs_stir(void) |
140 |
{ |
156 |
{ |
141 |
int done, fd, i; |
|
|
142 |
struct { |
157 |
struct { |
143 |
struct timeval tv; |
158 |
struct timeval tv; |
144 |
pid_t pid; |
159 |
u_char rnd[KEYSZ + IVSZ]; |
145 |
u_char rnd[KEYSIZE]; |
|
|
146 |
} rdat; |
160 |
} rdat; |
|
|
161 |
int done, fd; |
147 |
|
162 |
|
148 |
if (!rs_initialized) { |
|
|
149 |
arc4_init(); |
150 |
rs_initialized = 1; |
151 |
} |
152 |
done = 0; |
163 |
done = 0; |
153 |
if (arc4_sysctl((u_char *)&rdat, KEYSIZE) == KEYSIZE) |
164 |
if (_rs_sysctl((u_char *)&rdat, KEYSZ + IVSZ) == (KEYSZ + IVSZ)) |
154 |
done = 1; |
165 |
done = 1; |
|
|
166 |
|
155 |
if (!done) { |
167 |
if (!done) { |
156 |
fd = _open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0); |
168 |
fd = _open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0); |
157 |
if (fd >= 0) { |
169 |
if (fd >= 0) { |
158 |
if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) |
170 |
if (_read(fd, &rdat, (KEYSZ + IVSZ)) == (KEYSZ + IVSZ)) |
159 |
done = 1; |
171 |
done = 1; |
160 |
(void)_close(fd); |
172 |
(void)_close(fd); |
161 |
} |
173 |
} |
162 |
} |
174 |
} |
|
|
175 |
|
163 |
if (!done) { |
176 |
if (!done) { |
164 |
(void)gettimeofday(&rdat.tv, NULL); |
177 |
(void)gettimeofday(&rdat.tv, NULL); |
165 |
rdat.pid = getpid(); |
|
|
166 |
/* We'll just take whatever was on the stack too... */ |
178 |
/* We'll just take whatever was on the stack too... */ |
167 |
} |
179 |
} |
168 |
|
180 |
|
169 |
arc4_addrandom((u_char *)&rdat, KEYSIZE); |
181 |
if (!rs) { |
|
|
182 |
_rs_init((u_char *)&rdat, KEYSZ + IVSZ); |
183 |
} else { |
184 |
_rs_rekey((u_char *)&rdat, KEYSZ + IVSZ); |
185 |
} |
170 |
|
186 |
|
171 |
/* |
187 |
memset((u_char *)&rdat, 0, sizeof(rdat)); |
172 |
* Discard early keystream, as per recommendations in: |
188 |
|
173 |
* "(Not So) Random Shuffles of RC4" by Ilya Mironov. |
189 |
/* invalidate rs_buf */ |
174 |
*/ |
190 |
rs->rs_have = 0; |
175 |
for (i = 0; i < 1024; i++) |
191 |
memset(rsx->rs_buf, 0, RSBUFSZ); |
176 |
(void)arc4_getbyte(); |
192 |
|
177 |
arc4_count = 1600000; |
193 |
rs->rs_count = 1600000; |
178 |
} |
194 |
} |
179 |
|
195 |
|
180 |
static void |
196 |
static inline void |
181 |
arc4_stir_if_needed(void) |
197 |
_rs_stir_if_needed(size_t len) |
182 |
{ |
198 |
{ |
183 |
pid_t pid = getpid(); |
199 |
if (!rs || rs->rs_count <= len) |
184 |
|
200 |
_rs_stir(); |
185 |
if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { |
201 |
else |
186 |
arc4_stir_pid = pid; |
202 |
rs->rs_count -= len; |
187 |
arc4_stir(); |
|
|
188 |
} |
189 |
} |
203 |
} |
190 |
|
204 |
|
191 |
static inline u_int8_t |
205 |
static inline void |
192 |
arc4_getbyte(void) |
206 |
_rs_rekey(u_char *dat, size_t datlen) |
193 |
{ |
207 |
{ |
194 |
u_int8_t si, sj; |
208 |
#ifndef KEYSTREAM_ONLY |
195 |
|
209 |
memset(rsx->rs_buf, 0, RSBUFSZ); |
196 |
rs.i = (rs.i + 1); |
210 |
#endif |
197 |
si = rs.s[rs.i]; |
211 |
|
198 |
rs.j = (rs.j + si); |
212 |
/* fill rs_buf with the keystream */ |
199 |
sj = rs.s[rs.j]; |
213 |
chacha_encrypt_bytes(&rsx->ctx, rsx->rs_buf, rsx->rs_buf, RSBUFSZ); |
200 |
rs.s[rs.i] = sj; |
214 |
/* mix in optional user provided data */ |
201 |
rs.s[rs.j] = si; |
215 |
if (dat) { |
202 |
return (rs.s[(si + sj) & 0xff]); |
216 |
size_t i, m; |
|
|
217 |
|
218 |
m = MIN(datlen, (KEYSZ + IVSZ)); |
219 |
for (i = 0; i < m; i++) |
220 |
rsx->rs_buf[i] ^= dat[i]; |
221 |
} |
222 |
/* immediatly reinit for backtracking resistance */ |
223 |
_rs_init(rsx->rs_buf, (KEYSZ + IVSZ)); |
224 |
memset(rsx->rs_buf, 0, (KEYSZ + IVSZ)); |
225 |
rs->rs_have = (RSBUFSZ - KEYSZ - IVSZ); |
203 |
} |
226 |
} |
204 |
|
227 |
|
205 |
static inline u_int32_t |
228 |
static inline void |
206 |
arc4_getword(void) |
229 |
_rs_random_buf(void *_buf, size_t n) |
207 |
{ |
230 |
{ |
208 |
u_int32_t val; |
231 |
u_char *buf = (u_char *)_buf; |
209 |
val = arc4_getbyte() << 24; |
232 |
u_char *keystream; |
210 |
val |= arc4_getbyte() << 16; |
233 |
size_t m; |
211 |
val |= arc4_getbyte() << 8; |
234 |
|
212 |
val |= arc4_getbyte(); |
235 |
_rs_stir_if_needed(n); |
213 |
return val; |
236 |
while (n > 0) { |
|
|
237 |
if (rs->rs_have > 0) { |
238 |
m = MIN(n, rs->rs_have); |
239 |
keystream = (rsx->rs_buf + RSBUFSZ - rs->rs_have); |
240 |
memcpy(buf, keystream, m); |
241 |
memset(keystream, 0, m); |
242 |
buf += m; |
243 |
n -= m; |
244 |
rs->rs_have -= m; |
245 |
} |
246 |
|
247 |
if (rs->rs_have == 0) |
248 |
_rs_rekey(NULL, 0); |
249 |
} |
214 |
} |
250 |
} |
215 |
|
251 |
|
216 |
void |
252 |
static inline void |
217 |
arc4random_stir(void) |
253 |
_rs_random_u32(u_int32_t *val) |
218 |
{ |
254 |
{ |
219 |
_ARC4_LOCK(); |
255 |
u_char *keystream; |
220 |
arc4_stir(); |
256 |
|
221 |
_ARC4_UNLOCK(); |
257 |
_rs_stir_if_needed(sizeof(*val)); |
|
|
258 |
if (rs->rs_have < sizeof(*val)) |
259 |
_rs_rekey(NULL, 0); |
260 |
keystream = (rsx->rs_buf + RSBUFSZ - rs->rs_have); |
261 |
memcpy(val, keystream, sizeof(*val)); |
262 |
memset(keystream, 0, sizeof(*val)); |
263 |
rs->rs_have -= sizeof(*val); |
222 |
} |
264 |
} |
223 |
|
265 |
|
224 |
void |
266 |
void |
225 |
arc4random_addrandom(u_char *dat, int datlen) |
267 |
arc4random_addrandom(u_char *dat, int datlen) |
226 |
{ |
268 |
{ |
|
|
269 |
int m; |
270 |
|
227 |
_ARC4_LOCK(); |
271 |
_ARC4_LOCK(); |
228 |
if (!rs_initialized) |
272 |
if (!rs) |
229 |
arc4_stir(); |
273 |
_rs_stir(); |
230 |
arc4_addrandom(dat, datlen); |
274 |
|
|
|
275 |
while (datlen > 0) { |
276 |
m = MIN(datlen, (KEYSZ + IVSZ)); |
277 |
_rs_rekey(dat, m); |
278 |
dat += m; |
279 |
datlen -= m; |
280 |
} |
231 |
_ARC4_UNLOCK(); |
281 |
_ARC4_UNLOCK(); |
232 |
} |
282 |
} |
233 |
|
283 |
|
Lines 235-244
u_int32_t
Link Here
|
235 |
arc4random(void) |
285 |
arc4random(void) |
236 |
{ |
286 |
{ |
237 |
u_int32_t val; |
287 |
u_int32_t val; |
|
|
288 |
|
238 |
_ARC4_LOCK(); |
289 |
_ARC4_LOCK(); |
239 |
arc4_count -= 4; |
290 |
_rs_random_u32(&val); |
240 |
arc4_stir_if_needed(); |
|
|
241 |
val = arc4_getword(); |
242 |
_ARC4_UNLOCK(); |
291 |
_ARC4_UNLOCK(); |
243 |
return val; |
292 |
return val; |
244 |
} |
293 |
} |
Lines 246-295
arc4random(void)
Link Here
|
246 |
void |
295 |
void |
247 |
arc4random_buf(void *_buf, size_t n) |
296 |
arc4random_buf(void *_buf, size_t n) |
248 |
{ |
297 |
{ |
249 |
u_char *buf = (u_char *)_buf; |
|
|
250 |
_ARC4_LOCK(); |
298 |
_ARC4_LOCK(); |
251 |
arc4_stir_if_needed(); |
299 |
_rs_random_buf(_buf, n); |
252 |
while (n--) { |
300 |
_ARC4_UNLOCK(); |
253 |
if (--arc4_count <= 0) |
301 |
} |
254 |
arc4_stir(); |
302 |
|
255 |
buf[n] = arc4_getbyte(); |
303 |
void |
256 |
} |
304 |
arc4random_stir(void) |
|
|
305 |
{ |
306 |
_ARC4_LOCK(); |
307 |
_rs_stir(); |
257 |
_ARC4_UNLOCK(); |
308 |
_ARC4_UNLOCK(); |
258 |
} |
309 |
} |
259 |
|
310 |
|
260 |
/* |
|
|
261 |
* Calculate a uniformly distributed random number less than upper_bound |
262 |
* avoiding "modulo bias". |
263 |
* |
264 |
* Uniformity is achieved by generating new random numbers until the one |
265 |
* returned is outside the range [0, 2**32 % upper_bound). This |
266 |
* guarantees the selected random number will be inside |
267 |
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) |
268 |
* after reduction modulo upper_bound. |
269 |
*/ |
270 |
u_int32_t |
311 |
u_int32_t |
271 |
arc4random_uniform(u_int32_t upper_bound) |
312 |
arc4random_uniform(u_int32_t upper_bound) |
272 |
{ |
313 |
{ |
273 |
u_int32_t r, min; |
314 |
u_int32_t r, min; |
274 |
|
315 |
|
275 |
if (upper_bound < 2) |
316 |
if (upper_bound < 2) |
276 |
return 0; |
317 |
return (0); |
277 |
|
318 |
|
278 |
/* 2**32 % x == (2**32 - x) % x */ |
319 |
/* 2**32 % x == (2**32 - x) % x */ |
279 |
min = -upper_bound % upper_bound; |
320 |
min = -upper_bound % upper_bound; |
|
|
321 |
|
280 |
/* |
322 |
/* |
281 |
* This could theoretically loop forever but each retry has |
323 |
* This could theorically loop forever but each retry has |
282 |
* p > 0.5 (worst case, usually far better) of selecting a |
324 |
* p > 0.5 (worst case, usually far better) of selecting a |
283 |
* number inside the range we need, so it should rarely need |
325 |
* number inside the range we need, so it should rarely need |
284 |
* to re-roll. |
326 |
* to re-roll. |
285 |
*/ |
327 |
*/ |
|
|
328 |
|
286 |
for (;;) { |
329 |
for (;;) { |
287 |
r = arc4random(); |
330 |
r = arc4random(); |
288 |
if (r >= min) |
331 |
if (r >= min) |
289 |
break; |
332 |
break; |
290 |
} |
333 |
} |
291 |
|
334 |
|
292 |
return r % upper_bound; |
335 |
return (r % upper_bound); |
293 |
} |
336 |
} |
294 |
|
337 |
|
295 |
#if 0 |
338 |
#if 0 |