]>
git.ipfire.org Git - thirdparty/dhcpcd.git/blob - compat/arc4random.c
d61d61ffa7885ed22f7886246506042625e53db4
1 /* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */
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>
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.
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.
23 * ChaCha based random number generator for OpenBSD.
27 * OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c
28 * lib/libc/crypt/arc4random.h
40 #include <sys/types.h>
43 #if defined(HAVE_OPENSSL)
44 #include <openssl/rand.h>
47 #define KEYSTREAM_ONLY
48 #include "chacha_private.h"
50 #define minimum(a, b) ((a) < (b) ? (a) : (b))
52 #if defined(__GNUC__) || defined(_MSC_VER)
53 #define inline __inline
54 #else /* __GNUC__ || _MSC_VER */
56 #endif /* !__GNUC__ && !_MSC_VER */
61 #define RSBUFSZ (16*BLOCKSZ)
63 #define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
65 /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
67 size_t rs_have
; /* valid bytes at end of rs_buf */
68 size_t rs_count
; /* bytes till reseed */
71 /* Maybe be preserved in fork children, if _rs_allocate() decides. */
73 chacha_ctx rs_chacha
; /* chacha context for random keystream */
74 u_char rs_buf
[RSBUFSZ
]; /* keystream blocks */
77 static int _dhcpcd_rand_fd
= -1; /* /dev/urandom fd */
79 static int _dhcpcd_getentropy(void *, size_t);
80 static inline int _rs_allocate(struct _rs
**, struct _rsx
**);
82 /* dhcpcd needs to hold onto the fd at fork due to privsep */
84 static inline void _rs_forkdetect(void);
86 #define _rs_forkdetect()
87 #define _rs_forkhandler()
90 /* Inline "arc4random.h" */
91 #include <sys/types.h>
94 static inline void _rs_rekey(u_char
*dat
, size_t datlen
);
96 /* dhcpcd isn't multithreaded */
98 #define _ARC4_UNLOCK()
101 _dhcpcd_getentropy(void *buf
, size_t length
)
104 uint8_t *rand
= (uint8_t *)buf
;
106 #if defined (HAVE_OPENSSL)
107 if (RAND_priv_bytes(buf
, (int)length
) == 1)
111 if (length
< sizeof(tv
)) {
112 gettimeofday(&tv
, NULL
);
113 memcpy(buf
, &tv
, sizeof(tv
));
114 length
-= sizeof(tv
);
117 if (_dhcpcd_rand_fd
== -1)
118 _dhcpcd_rand_fd
= open("/dev/urandom", O_RDONLY
| O_NONBLOCK
);
119 if (_dhcpcd_rand_fd
!= -1) {
120 /* coverity[check_return] */
121 (void)read(_dhcpcd_rand_fd
, rand
, length
);
124 /* Never fail. If there is an error reading from /dev/urandom,
125 * just use what is on the stack. */
130 _getentropy_fail(void)
136 static volatile sig_atomic_t _rs_forked
;
139 _rs_forkhandler(void)
147 static pid_t _rs_pid
= 0;
148 pid_t pid
= getpid();
150 /* XXX unusual calls to clone() can bypass checks */
151 if (_rs_pid
== 0 || _rs_pid
== 1 || _rs_pid
!= pid
|| _rs_forked
) {
155 memset(rs
, 0, sizeof(*rs
));
161 _rs_allocate(struct _rs
**rsp
, struct _rsx
**rsxp
)
163 if ((*rsp
= mmap(NULL
, sizeof(**rsp
), PROT_READ
|PROT_WRITE
,
164 MAP_ANON
|MAP_PRIVATE
, -1, 0)) == MAP_FAILED
)
167 if ((*rsxp
= mmap(NULL
, sizeof(**rsxp
), PROT_READ
|PROT_WRITE
,
168 MAP_ANON
|MAP_PRIVATE
, -1, 0)) == MAP_FAILED
) {
169 munmap(*rsp
, sizeof(**rsp
));
179 _rs_init(u_char
*buf
, size_t n
)
181 if (n
< KEYSZ
+ IVSZ
)
185 if (_rs_allocate(&rs
, &rsx
) == -1)
189 chacha_keysetup(&rsx
->rs_chacha
, buf
, KEYSZ
* 8);
190 chacha_ivsetup(&rsx
->rs_chacha
, buf
+ KEYSZ
);
196 u_char rnd
[KEYSZ
+ IVSZ
];
197 uint32_t rekey_fuzz
= 0;
199 if (_dhcpcd_getentropy(rnd
, sizeof rnd
) == -1)
203 _rs_init(rnd
, sizeof(rnd
));
205 _rs_rekey(rnd
, sizeof(rnd
));
206 #if defined(HAVE_EXPLICIT_BZERO)
207 explicit_bzero(rnd
, sizeof(rnd
)); /* discard source seed */
208 #elif defined(HAVE_MEMSET_EXPLICIT)
209 (void)memset_explicit(rnd
, 0, sizeof(rnd
));
210 #elif defined(HAVE_MEMSET_S)
211 (void)memset_s(rnd
, sizeof(rnd
), 0, sizeof(rnd
));
213 #warning potentially insecure use of memset discarding the source seed
214 (void)memset(rnd
, 0, sizeof(rnd
)); /* discard source seed */
217 /* invalidate rs_buf */
219 memset(rsx
->rs_buf
, 0, sizeof(rsx
->rs_buf
));
221 /* rekey interval should not be predictable */
222 chacha_encrypt_bytes(&rsx
->rs_chacha
, (uint8_t *)&rekey_fuzz
,
223 (uint8_t *)&rekey_fuzz
, sizeof(rekey_fuzz
));
224 rs
->rs_count
= REKEY_BASE
+ (rekey_fuzz
% REKEY_BASE
);
228 _rs_stir_if_needed(size_t len
)
231 if (!rs
|| rs
->rs_count
<= len
)
233 if (rs
->rs_count
<= len
)
240 _rs_rekey(u_char
*dat
, size_t datlen
)
242 #ifndef KEYSTREAM_ONLY
243 memset(rsx
->rs_buf
, 0, sizeof(rsx
->rs_buf
));
245 /* fill rs_buf with the keystream */
246 chacha_encrypt_bytes(&rsx
->rs_chacha
, rsx
->rs_buf
,
247 rsx
->rs_buf
, sizeof(rsx
->rs_buf
));
248 /* mix in optional user provided data */
252 m
= minimum(datlen
, KEYSZ
+ IVSZ
);
253 for (i
= 0; i
< m
; i
++)
254 rsx
->rs_buf
[i
] ^= dat
[i
];
256 /* immediately reinit for backtracking resistance */
257 _rs_init(rsx
->rs_buf
, KEYSZ
+ IVSZ
);
258 memset(rsx
->rs_buf
, 0, KEYSZ
+ IVSZ
);
259 rs
->rs_have
= sizeof(rsx
->rs_buf
) - KEYSZ
- IVSZ
;
263 _rs_random_buf(void *_buf
, size_t n
)
265 u_char
*buf
= (u_char
*)_buf
;
269 _rs_stir_if_needed(n
);
271 if (rs
->rs_have
> 0) {
272 m
= minimum(n
, rs
->rs_have
);
273 keystream
= rsx
->rs_buf
+ sizeof(rsx
->rs_buf
)
275 memcpy(buf
, keystream
, m
);
276 memset(keystream
, 0, m
);
281 if (rs
->rs_have
== 0)
287 _rs_random_u32(uint32_t *val
)
291 _rs_stir_if_needed(sizeof(*val
));
292 if (rs
->rs_have
< sizeof(*val
))
294 keystream
= rsx
->rs_buf
+ sizeof(rsx
->rs_buf
) - rs
->rs_have
;
295 memcpy(val
, keystream
, sizeof(*val
));
296 memset(keystream
, 0, sizeof(*val
));
297 rs
->rs_have
-= sizeof(*val
);
306 _rs_random_u32(&val
);
312 arc4random_buf(void *buf
, size_t n
)
315 _rs_random_buf(buf
, n
);