Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libc/gen/arc4random.c
Show All 21 Lines | |||||
/* | /* | ||||
* ChaCha based random number generator for OpenBSD. | * ChaCha based random number generator for OpenBSD. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "namespace.h" | #include "namespace.h" | ||||
#if defined(__FreeBSD__) | |||||
#include <assert.h> | |||||
#endif | |||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
Show All 25 Lines | static struct _rs { | ||||
size_t rs_have; /* valid bytes at end of rs_buf */ | size_t rs_have; /* valid bytes at end of rs_buf */ | ||||
size_t rs_count; /* bytes till reseed */ | size_t rs_count; /* bytes till reseed */ | ||||
} *rs; | } *rs; | ||||
/* Maybe be preserved in fork children, if _rs_allocate() decides. */ | /* Maybe be preserved in fork children, if _rs_allocate() decides. */ | ||||
static struct _rsx { | static struct _rsx { | ||||
chacha_ctx rs_chacha; /* chacha context for random keystream */ | chacha_ctx rs_chacha; /* chacha context for random keystream */ | ||||
u_char rs_buf[RSBUFSZ]; /* keystream blocks */ | u_char rs_buf[RSBUFSZ]; /* keystream blocks */ | ||||
#ifdef __FreeBSD__ | |||||
uint32_t rs_seed_generation; /* 32-bit userspace RNG version */ | |||||
#endif | |||||
} *rsx; | } *rsx; | ||||
static inline int _rs_allocate(struct _rs **, struct _rsx **); | static inline int _rs_allocate(struct _rs **, struct _rsx **); | ||||
static inline void _rs_forkdetect(void); | static inline void _rs_forkdetect(void); | ||||
#include "arc4random.h" | #include "arc4random.h" | ||||
static inline void _rs_rekey(u_char *dat, size_t datlen); | static inline void _rs_rekey(u_char *dat, size_t datlen); | ||||
Show All 12 Lines | _rs_init(u_char *buf, size_t n) | ||||
chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); | chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); | ||||
} | } | ||||
static void | static void | ||||
_rs_stir(void) | _rs_stir(void) | ||||
{ | { | ||||
u_char rnd[KEYSZ + IVSZ]; | u_char rnd[KEYSZ + IVSZ]; | ||||
#if defined(__FreeBSD__) | |||||
bool need_init; | |||||
/* | |||||
* De-couple allocation (which locates the vdso_fxrngp pointer in | |||||
* auxinfo) from initialization. This allows us to read the root seed | |||||
* version before we fetch system entropy, maintaining the invariant | |||||
* that the PRF was seeded with entropy from rs_seed_generation or a | |||||
* later generation. But never seeded from an earlier generation. | |||||
* This invariant prevents us from missing a root reseed event. | |||||
*/ | |||||
need_init = false; | |||||
if (rs == NULL) { | |||||
if (_rs_allocate(&rs, &rsx) == -1) | |||||
abort(); | |||||
need_init = true; | |||||
} | |||||
/* | |||||
* Transition period: new userspace on old kernel. This should become | |||||
* a hard error at some point, if the scheme is adopted. | |||||
*/ | |||||
if (vdso_fxrngp != NULL) | |||||
rsx->rs_seed_generation = | |||||
fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32); | |||||
#endif | |||||
if (getentropy(rnd, sizeof rnd) == -1) | if (getentropy(rnd, sizeof rnd) == -1) | ||||
_getentropy_fail(); | _getentropy_fail(); | ||||
#if !defined(__FreeBSD__) | |||||
if (!rs) | if (!rs) | ||||
_rs_init(rnd, sizeof(rnd)); | _rs_init(rnd, sizeof(rnd)); | ||||
#else /* __FreeBSD__ */ | |||||
assert(rs != NULL); | |||||
if (need_init) | |||||
_rs_init(rnd, sizeof(rnd)); | |||||
#endif | |||||
else | else | ||||
_rs_rekey(rnd, sizeof(rnd)); | _rs_rekey(rnd, sizeof(rnd)); | ||||
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ | explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ | ||||
/* invalidate rs_buf */ | /* invalidate rs_buf */ | ||||
rs->rs_have = 0; | rs->rs_have = 0; | ||||
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); | memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); | ||||
▲ Show 20 Lines • Show All 94 Lines • Show Last 20 Lines |