View | Details | Raw Unified | Return to bug 3467 | Differences between
and this patch

Collapse All | Expand All

(-)a/openbsd-compat/arc4random.c (-103 / +89 lines)
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
(-)a/openbsd-compat/arc4random.h (+79 lines)
Line 0 Link Here
1
/*	$OpenBSD: arc4random_linux.h,v 1.12 2019/07/11 10:37:28 inoguchi Exp $	*/
2
3
/*
4
 * Copyright (c) 1996, David Mazieres <dm@uun.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>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
/*
23
 * Stub functions for portability.  From LibreSSL with some adaptations.
24
 */
25
26
#include <sys/mman.h>
27
28
#include <signal.h>
29
30
/* OpenSSH isn't multithreaded */
31
#define _ARC4_LOCK()
32
#define _ARC4_UNLOCK()
33
#define _ARC4_ATFORK(f)
34
35
static inline void
36
_getentropy_fail(void)
37
{
38
	fatal("getentropy failed");
39
}
40
41
static volatile sig_atomic_t _rs_forked;
42
43
static inline void
44
_rs_forkhandler(void)
45
{
46
	_rs_forked = 1;
47
}
48
49
static inline void
50
_rs_forkdetect(void)
51
{
52
	static pid_t _rs_pid = 0;
53
	pid_t pid = getpid();
54
55
	if (_rs_pid == 0 || _rs_pid == 1 || _rs_pid != pid || _rs_forked) {
56
		_rs_pid = pid;
57
		_rs_forked = 0;
58
		if (rs)
59
			memset(rs, 0, sizeof(*rs));
60
	}
61
}
62
63
static inline int
64
_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
65
{
66
	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
67
	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
68
		return (-1);
69
70
	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
71
	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
72
		munmap(*rsp, sizeof(**rsp));
73
		*rsp = NULL;
74
		return (-1);
75
	}
76
77
	_ARC4_ATFORK(_rs_forkhandler);
78
	return (0);
79
}
(-)a/openbsd-compat/openbsd-compat.h (-7 / +6 lines)
Lines 218-236 int writev(int, struct iovec *, int); Link Here
218
int getpeereid(int , uid_t *, gid_t *);
218
int getpeereid(int , uid_t *, gid_t *);
219
#endif
219
#endif
220
220
221
#ifdef HAVE_ARC4RANDOM
221
#ifndef HAVE_ARC4RANDOM
222
# ifndef HAVE_ARC4RANDOM_STIR
222
uint32_t arc4random(void);
223
#  define arc4random_stir()
224
# endif
225
#else
226
unsigned int arc4random(void);
227
void arc4random_stir(void);
228
#endif /* !HAVE_ARC4RANDOM */
223
#endif /* !HAVE_ARC4RANDOM */
229
224
230
#ifndef HAVE_ARC4RANDOM_BUF
225
#ifndef HAVE_ARC4RANDOM_BUF
231
void arc4random_buf(void *, size_t);
226
void arc4random_buf(void *, size_t);
232
#endif
227
#endif
233
228
229
#ifndef HAVE_ARC4RANDOM_STIR
230
# define arc4random_stir()
231
#endif
232
234
#ifndef HAVE_ARC4RANDOM_UNIFORM
233
#ifndef HAVE_ARC4RANDOM_UNIFORM
235
uint32_t arc4random_uniform(uint32_t);
234
uint32_t arc4random_uniform(uint32_t);
236
#endif
235
#endif

Return to bug 3467