From: "Theo de Raadt" Subject: Re: Low Entropy at boot To: Sylvain Cc: tech@openbsd.org Date: Wed, 21 Aug 2024 13:39:36 -0600 Sylvain wrote: > I was installing one of the BSD on an old laptop the other day and got a message > about the entropy sources being insufficient to ensure proper crypto configuration. You don't show the exact message, but your interpretation is not correct. A previous boot saves a file on-disk, which is retrieved by the bootblocks. When the bootblocks pickup this file for a kernel run, they mark it as having been used. This allows the bootblocks to warn if it is reused. That is an initial seed. It is immediately augmented through various mechanisms and you do NOT make it anywhere near userland before it is augmented suffiently that there is no concern. In fact, I CAN PROMISE YOU, that a re-used seed is NO CONCERN AT ALL, due to the additional augmentation that happens automatically in the kernel. As to why you saw the seed? Some forms of unclean crash, or failed hibernate recovery, can cause this event to occur because a new file was not placed at the right moment. We could remove that warning message (which is misinterpreted nowadays), but as we improve hibernate it remains useful........ What you have below is completely unneccessary and incorrect placement of a solution to a tiny problem that does not exist in practice. > This got me thinking about the true RNG I created that uses multiple threads and > concurrent memory access to maintain an unstable and unpredictable state. This > could be used at boot to supplement or replace a weak hardware generator. > > I included my source code to program that uses this technique to extract entropy > from user space. I call this "synthetic chaos”. I figured if any operating system is > interested in exploring this, it has to be OpenBSD. > > I am writing this in case someone think it can help alleviate deficiencies or > unknown own flaws in hardware generators. > > This is not an algorithm, it is really three programs running concurrently and using > unmitigated memory access in a clever way that allow imperfections in hardware to > be observed all the way into the software layer. > > I hope it can be useful. > > Sylvain Saucier, > Artist and philosopher. > sylvain@sysau.art > > > /* > Public Domain, please append your contributions, respectfully. > Version 1.0 - Sylvain Saucier (sylvain@sysau.com) - Original author > */ > > #include > #include > #include > #include > > typedef struct { > volatile uint64_t * s_output; > volatile uint64_t * s_input; > int pause; > int stop; > pthread_mutex_t mutex; > pthread_t thread; > } > _C4_node; > > typedef struct { > volatile uint64_t shared_io[3]; > _C4_node t[3]; > } > _C4_state; > > //replace with large prime numbers between (2^63 > 2^64) for best results > int C4_hash_algo(volatile uint64_t * in, volatile uint64_t * out) { > uint64_t acc = 1; > uint64_t primes[128] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, > 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, > 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, > 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, > 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, > 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, > 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, > 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, > 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647}; > > for (int bit = 0; bit < 64; bit++) { > * in = ( * in << 13) | ( * in >> (64 - 13)); > acc = (acc << bit) | (acc >> (64 - bit)); > acc *= primes[(2 * bit) + (1 & * in)];* out += acc ^ * in; > }* out ^= acc; > return 0; > } > > void C4_pause(_C4_state * state) { > for (int thr = 0; thr < 3; thr++) { > pthread_mutex_lock( & (state -> t[thr].mutex)); > state -> t[thr].pause = 1; > } > } > > void C4_start(_C4_state * icm) { > for (int thr = 0; thr < 3; thr++) { > pthread_mutex_unlock( & (icm -> t[thr].mutex)); > } > } > > void * C4_main(void * raw) { > _C4_node * self__C4_state = (_C4_node * ) raw; > while (1) { > C4_hash_algo(self__C4_state -> s_output, self__C4_state -> s_input); > if (self__C4_state -> pause) { > if (!self__C4_state -> stop) pthread_exit(NULL); > self__C4_state -> pause = 0; > pthread_mutex_lock( & self__C4_state -> mutex); > pthread_mutex_unlock( & self__C4_state -> mutex); > } > } > return NULL; > } > > void init(_C4_state * s) { > for (int thr = 0; thr < 3; thr++) { > s -> shared_io[thr] = 0; > s -> t[thr].s_output = & (s -> shared_io[thr]); > s -> t[thr].s_input = & (s -> shared_io[(thr + 1) % 3]); > s -> t[thr].stop = 1; > s -> t[thr].pause = 1; > pthread_mutex_init( & (s -> t[thr].mutex), NULL); > pthread_mutex_lock( & (s -> t[thr].mutex)); > pthread_create( & (s -> t[thr].thread), NULL, & C4_main, & (s -> t[thr])); > } > C4_start(s); > usleep(100); > C4_pause(s); > } > > void fill(_C4_state * state, uint64_t * buffer, uint64_t length) { > C4_start(state); > uint64_t answer = 0; > for (int found = 0; found < length; found++) { > usleep(30); > for (int thr = 0; thr < 3; thr++) > answer ^= state -> shared_io[thr]; > buffer[found] = answer; > } > C4_pause(state); > } > > int main(int argc, > const char * argv[]) { > uint64_t out; > _C4_state state; > init( & state); > > while (1) { > fill( & state, & out, 1); > fwrite( & out, sizeof(uint64_t), 1, stdout); > } > return 0; > } >