Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/lib/util/arc4random.c
1532 views
1
/* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */
2
3
/*
4
* SPDX-License-Identifier: ISC
5
*
6
* Copyright (c) 1996, David Mazieres <[email protected]>
7
* Copyright (c) 2008, Damien Miller <[email protected]>
8
* Copyright (c) 2013, Markus Friedl <[email protected]>
9
* Copyright (c) 2014, Theo de Raadt <[email protected]>
10
*
11
* Permission to use, copy, modify, and distribute this software for any
12
* purpose with or without fee is hereby granted, provided that the above
13
* copyright notice and this permission notice appear in all copies.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
*/
23
24
/*
25
* ChaCha based random number generator for OpenBSD.
26
*/
27
28
#include <config.h>
29
30
#ifndef HAVE_ARC4RANDOM
31
32
#ifdef HAVE_SYS_RANDOM_H
33
# include <sys/random.h>
34
#endif
35
36
#include <fcntl.h>
37
#include <limits.h>
38
#include <signal.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
#if defined(HAVE_STDINT_H)
43
# include <stdint.h>
44
#elif defined(HAVE_INTTYPES_H)
45
# include <inttypes.h>
46
#endif
47
48
#include <sudo_compat.h>
49
#include <sudo_fatal.h>
50
#include <sudo_rand.h>
51
52
#define KEYSTREAM_ONLY
53
#include "chacha_private.h"
54
55
#define minimum(a, b) ((a) < (b) ? (a) : (b))
56
57
#ifdef __GNUC__
58
# define inline __inline
59
#else /* !__GNUC__ */
60
# define inline
61
#endif /* !__GNUC__ */
62
63
/* Sudo isn't multithreaded */
64
#define _ARC4_LOCK()
65
#define _ARC4_UNLOCK()
66
67
#define KEYSZ 32
68
#define IVSZ 8
69
#define BLOCKSZ 64
70
#define RSBUFSZ (16*BLOCKSZ)
71
static int rs_initialized;
72
static pid_t rs_stir_pid;
73
static chacha_ctx rs; /* chacha context for random keystream */
74
static u_char rs_buf[RSBUFSZ]; /* keystream blocks */
75
static size_t rs_have; /* valid bytes at end of rs_buf */
76
static size_t rs_count; /* bytes till reseed */
77
78
static inline void _rs_rekey(unsigned char *dat, size_t datlen);
79
80
static inline void
81
_rs_init(unsigned char *buf, size_t n)
82
{
83
if (n < KEYSZ + IVSZ)
84
return;
85
chacha_keysetup(&rs, buf, KEYSZ * 8, 0);
86
chacha_ivsetup(&rs, buf + KEYSZ);
87
}
88
89
static void
90
_rs_stir(void)
91
{
92
unsigned char rnd[KEYSZ + IVSZ];
93
94
if (getentropy(rnd, sizeof rnd) == -1)
95
sudo_fatal_nodebug("getentropy");
96
97
if (!rs_initialized) {
98
rs_initialized = 1;
99
_rs_init(rnd, sizeof(rnd));
100
} else
101
_rs_rekey(rnd, sizeof(rnd));
102
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
103
104
/* invalidate rs_buf */
105
rs_have = 0;
106
memset(rs_buf, 0, sizeof(rs_buf));
107
108
rs_count = 1600000;
109
}
110
111
static inline void
112
_rs_stir_if_needed(size_t len)
113
{
114
pid_t pid = getpid();
115
116
if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
117
rs_stir_pid = pid;
118
_rs_stir();
119
} else
120
rs_count -= len;
121
}
122
123
static inline void
124
_rs_rekey(unsigned char *dat, size_t datlen)
125
{
126
#ifndef KEYSTREAM_ONLY
127
memset(rs_buf, 0, sizeof(rs_buf));
128
#endif
129
/* fill rs_buf with the keystream */
130
chacha_encrypt_bytes(&rs, rs_buf, rs_buf, sizeof(rs_buf));
131
/* mix in optional user provided data */
132
if (dat) {
133
size_t i, m;
134
135
m = minimum(datlen, KEYSZ + IVSZ);
136
for (i = 0; i < m; i++)
137
rs_buf[i] ^= dat[i];
138
}
139
/* immediately reinit for backtracking resistance */
140
_rs_init(rs_buf, KEYSZ + IVSZ);
141
memset(rs_buf, 0, KEYSZ + IVSZ); // -V::512, 1086
142
rs_have = sizeof(rs_buf) - KEYSZ - IVSZ;
143
}
144
145
static inline void
146
_rs_random_buf(void *_buf, size_t n)
147
{
148
unsigned char *buf = _buf;
149
unsigned char *keystream;
150
size_t m;
151
152
_rs_stir_if_needed(n);
153
while (n > 0) {
154
if (rs_have > 0) {
155
m = minimum(n, rs_have);
156
keystream = rs_buf + sizeof(rs_buf) - rs_have;
157
memcpy(buf, keystream, m);
158
memset(keystream, 0, m);
159
buf += m;
160
n -= m;
161
rs_have -= m;
162
}
163
if (rs_have == 0)
164
_rs_rekey(NULL, 0);
165
}
166
}
167
168
static inline void
169
_rs_random_u32(uint32_t *val)
170
{
171
unsigned char *keystream;
172
173
_rs_stir_if_needed(sizeof(*val));
174
if (rs_have < sizeof(*val))
175
_rs_rekey(NULL, 0);
176
keystream = rs_buf + sizeof(rs_buf) - rs_have;
177
memcpy(val, keystream, sizeof(*val));
178
memset(keystream, 0, sizeof(*val));
179
rs_have -= sizeof(*val);
180
}
181
182
uint32_t
183
sudo_arc4random(void)
184
{
185
uint32_t val;
186
187
_ARC4_LOCK();
188
_rs_random_u32(&val);
189
_ARC4_UNLOCK();
190
return val;
191
}
192
193
void
194
sudo_arc4random_buf(void *buf, size_t n)
195
{
196
_ARC4_LOCK();
197
_rs_random_buf(buf, n);
198
_ARC4_UNLOCK();
199
}
200
201
#endif /* HAVE_ARC4RANDOM */
202
203