|
Lines 1-11
Link Here
|
| 1 |
/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */ |
1 |
/* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */ |
| 2 |
|
|
|
| 3 |
/* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */ |
| 4 |
|
2 |
|
| 5 |
/* |
3 |
/* |
| 6 |
* Copyright (c) 1996, David Mazieres <dm@uun.org> |
4 |
* Copyright (c) 1996, David Mazieres <dm@uun.org> |
| 7 |
* Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
5 |
* Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
| 8 |
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org> |
6 |
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org> |
|
|
7 |
* Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> |
| 9 |
* |
8 |
* |
| 10 |
* Permission to use, copy, modify, and distribute this software for any |
9 |
* Permission to use, copy, modify, and distribute this software for any |
| 11 |
* 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 24-67
Link Here
|
| 24 |
* ChaCha based random number generator for OpenBSD. |
23 |
* ChaCha based random number generator for OpenBSD. |
| 25 |
*/ |
24 |
*/ |
| 26 |
|
25 |
|
| 27 |
#include "includes.h" |
26 |
/* OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c */ |
| 28 |
|
27 |
|
| 29 |
#include <sys/types.h> |
28 |
#include "includes.h" |
| 30 |
|
29 |
|
| 31 |
#include <fcntl.h> |
30 |
#include <fcntl.h> |
|
|
31 |
#include <limits.h> |
| 32 |
#include <signal.h> |
| 33 |
#ifdef HAVE_STDINT_H |
| 34 |
#include <stdint.h> |
| 35 |
#endif |
| 32 |
#include <stdlib.h> |
36 |
#include <stdlib.h> |
| 33 |
#include <string.h> |
37 |
#include <string.h> |
| 34 |
#include <unistd.h> |
38 |
#include <unistd.h> |
|
|
39 |
#include <sys/types.h> |
| 40 |
#include <sys/time.h> |
| 35 |
|
41 |
|
| 36 |
#ifndef HAVE_ARC4RANDOM |
42 |
#ifndef HAVE_ARC4RANDOM |
| 37 |
|
43 |
|
| 38 |
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) |
|
|
| 39 |
|
| 40 |
#include "log.h" |
44 |
#include "log.h" |
|
|
45 |
#define DEF_WEAK(x) |
| 41 |
|
46 |
|
| 42 |
#define KEYSTREAM_ONLY |
47 |
#define KEYSTREAM_ONLY |
| 43 |
#include "chacha_private.h" |
48 |
#include "chacha_private.h" |
| 44 |
|
49 |
|
| 45 |
#ifdef __GNUC__ |
50 |
#define minimum(a, b) ((a) < (b) ? (a) : (b)) |
|
|
51 |
|
| 52 |
#if defined(__GNUC__) || defined(_MSC_VER) |
| 46 |
#define inline __inline |
53 |
#define inline __inline |
| 47 |
#else /* !__GNUC__ */ |
54 |
#else /* __GNUC__ || _MSC_VER */ |
| 48 |
#define inline |
55 |
#define inline |
| 49 |
#endif /* !__GNUC__ */ |
56 |
#endif /* !__GNUC__ && !_MSC_VER */ |
| 50 |
|
|
|
| 51 |
/* OpenSSH isn't multithreaded */ |
| 52 |
#define _ARC4_LOCK() |
| 53 |
#define _ARC4_UNLOCK() |
| 54 |
|
57 |
|
| 55 |
#define KEYSZ 32 |
58 |
#define KEYSZ 32 |
| 56 |
#define IVSZ 8 |
59 |
#define IVSZ 8 |
| 57 |
#define BLOCKSZ 64 |
60 |
#define BLOCKSZ 64 |
| 58 |
#define RSBUFSZ (16*BLOCKSZ) |
61 |
#define RSBUFSZ (16*BLOCKSZ) |
| 59 |
static int rs_initialized; |
62 |
|
| 60 |
static pid_t rs_stir_pid; |
63 |
#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */ |
| 61 |
static chacha_ctx rs; /* chacha context for random keystream */ |
64 |
|
| 62 |
static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ |
65 |
/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */ |
| 63 |
static size_t rs_have; /* valid bytes at end of rs_buf */ |
66 |
static struct _rs { |
| 64 |
static size_t rs_count; /* bytes till reseed */ |
67 |
size_t rs_have; /* valid bytes at end of rs_buf */ |
|
|
68 |
size_t rs_count; /* bytes till reseed */ |
| 69 |
} *rs; |
| 70 |
|
| 71 |
/* Maybe be preserved in fork children, if _rs_allocate() decides. */ |
| 72 |
static struct _rsx { |
| 73 |
chacha_ctx rs_chacha; /* chacha context for random keystream */ |
| 74 |
u_char rs_buf[RSBUFSZ]; /* keystream blocks */ |
| 75 |
} *rsx; |
| 76 |
|
| 77 |
static inline int _rs_allocate(struct _rs **, struct _rsx **); |
| 78 |
static inline void _rs_forkdetect(void); |
| 79 |
#include "arc4random.h" |
| 65 |
|
80 |
|
| 66 |
static inline void _rs_rekey(u_char *dat, size_t datlen); |
81 |
static inline void _rs_rekey(u_char *dat, size_t datlen); |
| 67 |
|
82 |
|
|
Lines 70-203
_rs_init(u_char *buf, size_t n)
Link Here
|
| 70 |
{ |
85 |
{ |
| 71 |
if (n < KEYSZ + IVSZ) |
86 |
if (n < KEYSZ + IVSZ) |
| 72 |
return; |
87 |
return; |
| 73 |
chacha_keysetup(&rs, buf, KEYSZ * 8); |
88 |
|
| 74 |
chacha_ivsetup(&rs, buf + KEYSZ); |
89 |
if (rs == NULL) { |
|
|
90 |
if (_rs_allocate(&rs, &rsx) == -1) |
| 91 |
_exit(1); |
| 92 |
} |
| 93 |
|
| 94 |
chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); |
| 95 |
chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); |
| 75 |
} |
96 |
} |
| 76 |
|
97 |
|
| 77 |
static void |
98 |
static void |
| 78 |
_rs_stir(void) |
99 |
_rs_stir(void) |
| 79 |
{ |
100 |
{ |
| 80 |
u_char rnd[KEYSZ + IVSZ]; |
101 |
u_char rnd[KEYSZ + IVSZ]; |
|
|
102 |
uint32_t rekey_fuzz = 0; |
| 81 |
|
103 |
|
| 82 |
if (getentropy(rnd, sizeof rnd) == -1) |
104 |
if (getentropy(rnd, sizeof rnd) == -1) |
| 83 |
fatal("getentropy failed"); |
105 |
_getentropy_fail(); |
| 84 |
|
106 |
|
| 85 |
if (!rs_initialized) { |
107 |
if (!rs) |
| 86 |
rs_initialized = 1; |
|
|
| 87 |
_rs_init(rnd, sizeof(rnd)); |
108 |
_rs_init(rnd, sizeof(rnd)); |
| 88 |
} else |
109 |
else |
| 89 |
_rs_rekey(rnd, sizeof(rnd)); |
110 |
_rs_rekey(rnd, sizeof(rnd)); |
| 90 |
explicit_bzero(rnd, sizeof(rnd)); |
111 |
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ |
| 91 |
|
112 |
|
| 92 |
/* invalidate rs_buf */ |
113 |
/* invalidate rs_buf */ |
| 93 |
rs_have = 0; |
114 |
rs->rs_have = 0; |
| 94 |
memset(rs_buf, 0, RSBUFSZ); |
115 |
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); |
| 95 |
|
116 |
|
| 96 |
rs_count = 1600000; |
117 |
/* rekey interval should not be predictable */ |
|
|
118 |
chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz, |
| 119 |
(uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz)); |
| 120 |
rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE); |
| 97 |
} |
121 |
} |
| 98 |
|
122 |
|
| 99 |
static inline void |
123 |
static inline void |
| 100 |
_rs_stir_if_needed(size_t len) |
124 |
_rs_stir_if_needed(size_t len) |
| 101 |
{ |
125 |
{ |
| 102 |
pid_t pid = getpid(); |
126 |
_rs_forkdetect(); |
| 103 |
|
127 |
if (!rs || rs->rs_count <= len) |
| 104 |
if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { |
|
|
| 105 |
rs_stir_pid = pid; |
| 106 |
_rs_stir(); |
128 |
_rs_stir(); |
| 107 |
} else |
129 |
if (rs->rs_count <= len) |
| 108 |
rs_count -= len; |
130 |
rs->rs_count = 0; |
|
|
131 |
else |
| 132 |
rs->rs_count -= len; |
| 109 |
} |
133 |
} |
| 110 |
|
134 |
|
| 111 |
static inline void |
135 |
static inline void |
| 112 |
_rs_rekey(u_char *dat, size_t datlen) |
136 |
_rs_rekey(u_char *dat, size_t datlen) |
| 113 |
{ |
137 |
{ |
| 114 |
#ifndef KEYSTREAM_ONLY |
138 |
#ifndef KEYSTREAM_ONLY |
| 115 |
memset(rs_buf, 0,RSBUFSZ); |
139 |
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); |
| 116 |
#endif |
140 |
#endif |
| 117 |
/* fill rs_buf with the keystream */ |
141 |
/* fill rs_buf with the keystream */ |
| 118 |
chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); |
142 |
chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, |
|
|
143 |
rsx->rs_buf, sizeof(rsx->rs_buf)); |
| 119 |
/* mix in optional user provided data */ |
144 |
/* mix in optional user provided data */ |
| 120 |
if (dat) { |
145 |
if (dat) { |
| 121 |
size_t i, m; |
146 |
size_t i, m; |
| 122 |
|
147 |
|
| 123 |
m = MINIMUM(datlen, KEYSZ + IVSZ); |
148 |
m = minimum(datlen, KEYSZ + IVSZ); |
| 124 |
for (i = 0; i < m; i++) |
149 |
for (i = 0; i < m; i++) |
| 125 |
rs_buf[i] ^= dat[i]; |
150 |
rsx->rs_buf[i] ^= dat[i]; |
| 126 |
} |
151 |
} |
| 127 |
/* immediately reinit for backtracking resistance */ |
152 |
/* immediately reinit for backtracking resistance */ |
| 128 |
_rs_init(rs_buf, KEYSZ + IVSZ); |
153 |
_rs_init(rsx->rs_buf, KEYSZ + IVSZ); |
| 129 |
memset(rs_buf, 0, KEYSZ + IVSZ); |
154 |
memset(rsx->rs_buf, 0, KEYSZ + IVSZ); |
| 130 |
rs_have = RSBUFSZ - KEYSZ - IVSZ; |
155 |
rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; |
| 131 |
} |
156 |
} |
| 132 |
|
157 |
|
| 133 |
static inline void |
158 |
static inline void |
| 134 |
_rs_random_buf(void *_buf, size_t n) |
159 |
_rs_random_buf(void *_buf, size_t n) |
| 135 |
{ |
160 |
{ |
| 136 |
u_char *buf = (u_char *)_buf; |
161 |
u_char *buf = (u_char *)_buf; |
|
|
162 |
u_char *keystream; |
| 137 |
size_t m; |
163 |
size_t m; |
| 138 |
|
164 |
|
| 139 |
_rs_stir_if_needed(n); |
165 |
_rs_stir_if_needed(n); |
| 140 |
while (n > 0) { |
166 |
while (n > 0) { |
| 141 |
if (rs_have > 0) { |
167 |
if (rs->rs_have > 0) { |
| 142 |
m = MINIMUM(n, rs_have); |
168 |
m = minimum(n, rs->rs_have); |
| 143 |
memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); |
169 |
keystream = rsx->rs_buf + sizeof(rsx->rs_buf) |
| 144 |
memset(rs_buf + RSBUFSZ - rs_have, 0, m); |
170 |
- rs->rs_have; |
|
|
171 |
memcpy(buf, keystream, m); |
| 172 |
memset(keystream, 0, m); |
| 145 |
buf += m; |
173 |
buf += m; |
| 146 |
n -= m; |
174 |
n -= m; |
| 147 |
rs_have -= m; |
175 |
rs->rs_have -= m; |
| 148 |
} |
176 |
} |
| 149 |
if (rs_have == 0) |
177 |
if (rs->rs_have == 0) |
| 150 |
_rs_rekey(NULL, 0); |
178 |
_rs_rekey(NULL, 0); |
| 151 |
} |
179 |
} |
| 152 |
} |
180 |
} |
| 153 |
|
181 |
|
| 154 |
static inline void |
182 |
static inline void |
| 155 |
_rs_random_u32(u_int32_t *val) |
183 |
_rs_random_u32(uint32_t *val) |
| 156 |
{ |
184 |
{ |
|
|
185 |
u_char *keystream; |
| 186 |
|
| 157 |
_rs_stir_if_needed(sizeof(*val)); |
187 |
_rs_stir_if_needed(sizeof(*val)); |
| 158 |
if (rs_have < sizeof(*val)) |
188 |
if (rs->rs_have < sizeof(*val)) |
| 159 |
_rs_rekey(NULL, 0); |
189 |
_rs_rekey(NULL, 0); |
| 160 |
memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); |
190 |
keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; |
| 161 |
memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); |
191 |
memcpy(val, keystream, sizeof(*val)); |
| 162 |
rs_have -= sizeof(*val); |
192 |
memset(keystream, 0, sizeof(*val)); |
| 163 |
return; |
193 |
rs->rs_have -= sizeof(*val); |
| 164 |
} |
194 |
} |
| 165 |
|
195 |
|
| 166 |
void |
196 |
uint32_t |
| 167 |
arc4random_stir(void) |
|
|
| 168 |
{ |
| 169 |
_ARC4_LOCK(); |
| 170 |
_rs_stir(); |
| 171 |
_ARC4_UNLOCK(); |
| 172 |
} |
| 173 |
|
| 174 |
void |
| 175 |
arc4random_addrandom(u_char *dat, int datlen) |
| 176 |
{ |
| 177 |
int m; |
| 178 |
|
| 179 |
_ARC4_LOCK(); |
| 180 |
if (!rs_initialized) |
| 181 |
_rs_stir(); |
| 182 |
while (datlen > 0) { |
| 183 |
m = MINIMUM(datlen, KEYSZ + IVSZ); |
| 184 |
_rs_rekey(dat, m); |
| 185 |
dat += m; |
| 186 |
datlen -= m; |
| 187 |
} |
| 188 |
_ARC4_UNLOCK(); |
| 189 |
} |
| 190 |
|
| 191 |
u_int32_t |
| 192 |
arc4random(void) |
197 |
arc4random(void) |
| 193 |
{ |
198 |
{ |
| 194 |
u_int32_t val; |
199 |
uint32_t val; |
| 195 |
|
200 |
|
| 196 |
_ARC4_LOCK(); |
201 |
_ARC4_LOCK(); |
| 197 |
_rs_random_u32(&val); |
202 |
_rs_random_u32(&val); |
| 198 |
_ARC4_UNLOCK(); |
203 |
_ARC4_UNLOCK(); |
| 199 |
return val; |
204 |
return val; |
| 200 |
} |
205 |
} |
|
|
206 |
DEF_WEAK(arc4random); |
| 201 |
|
207 |
|
| 202 |
/* |
208 |
/* |
| 203 |
* If we are providing arc4random, then we can provide a more efficient |
209 |
* If we are providing arc4random, then we can provide a more efficient |
|
Lines 211-216
arc4random_buf(void *buf, size_t n)
Link Here
|
| 211 |
_rs_random_buf(buf, n); |
217 |
_rs_random_buf(buf, n); |
| 212 |
_ARC4_UNLOCK(); |
218 |
_ARC4_UNLOCK(); |
| 213 |
} |
219 |
} |
|
|
220 |
DEF_WEAK(arc4random_buf); |
| 214 |
# endif /* !HAVE_ARC4RANDOM_BUF */ |
221 |
# endif /* !HAVE_ARC4RANDOM_BUF */ |
| 215 |
#endif /* !HAVE_ARC4RANDOM */ |
222 |
#endif /* !HAVE_ARC4RANDOM */ |
| 216 |
|
223 |
|
|
Lines 233-256
arc4random_buf(void *_buf, size_t n)
Link Here
|
| 233 |
} |
240 |
} |
| 234 |
#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */ |
241 |
#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */ |
| 235 |
|
242 |
|
| 236 |
#if 0 |
|
|
| 237 |
/*-------- Test code for i386 --------*/ |
| 238 |
#include <stdio.h> |
| 239 |
#include <machine/pctr.h> |
| 240 |
int |
| 241 |
main(int argc, char **argv) |
| 242 |
{ |
| 243 |
const int iter = 1000000; |
| 244 |
int i; |
| 245 |
pctrval v; |
| 246 |
|
| 247 |
v = rdtsc(); |
| 248 |
for (i = 0; i < iter; i++) |
| 249 |
arc4random(); |
| 250 |
v = rdtsc() - v; |
| 251 |
v /= iter; |
| 252 |
|
| 253 |
printf("%qd cycles\n", v); |
| 254 |
exit(0); |
| 255 |
} |
| 256 |
#endif |