Thanks for making it. Really amazing resource. It would be awesome if the pdf has bookmarks/table of contents for easy navigation.
Able to hook up atmega32 to breadboard(bare) and communicate with it via avrdude on Linux. Today and tomorrow I am planning to read couple of chapters from Make: AVR Programming. Hope I will learn something new there.
Planning to learn/practice davinci resolve
The details regarding this change can be found here: https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git/commit/?id=186873c549df11b63e17062f863654e1501e1524
Basically this changes what was before a global structure (actually, a per-numa node structure) into a per-cpu structure, which meant a lot of locks in the fast path could disappear. This unsurprisingly results in performance boosts when you have many different CPUs trying to getrandom() at the same time. I didn’t expect some test to result in gains this big, but I suppose it makes sense, because in addition to less locking, this is also, I assume, a lot more cache friendly.
The main reasosn I made this change weren’t actually directly for performance, but was for a few other nitpicky reasons:
The solution – which was just to have a 32-byte per-cpu key – lead to a whole lot of this simplifying. The first 32 bytes of RNG output returned now requires just disabling preemption. Then after that, subsequent bytes can be generated with no locks at all, totally “detached”. Every five minutes, the whole thing is refreshed with new entropy, and this requires taking locks to get all that tidy. But that’s only on a single call once ever five minutes, so it’s basically not noticeable.
I should note that the basic “fast key erasure RNG” scheme used here isn’t novel; rather, it stems from djb’s post here https://blog.cr.yp.to/20170723-random.html. My addition is making it parallelize to a multi-cpu environment.
I have a couple questions about that, actually.
/dev/{,u}random
, is that also subject to the same 5 minute interval, or is the RNG immediately rekeyed?1a) Because that’s how it was before, and I’m trying to change the fewest amount of things at once as part of this RNG rejuvenation effort. My general feeling is that the work I’m doing is tolerated so long as it’s incremental. This also makes bisection and such easier. So if that does change at some point, it’ll need to be accompanied with an explanation that fully understands why it was that way before and the history around that decision, and why those decisions should be revisited.
1b) In order to avoid the “premature next” problem, in which the RNG is reseeded after only, say, 9 new bits of entropy have been added, enabling those 9 bits to be bruteforced, and if this happens over and over, the “slow trickle” means there’s no state recovery. Linux current deploys two flawed mechanisms to prevent this. The first is that we “count” entropy bits added, and don’t reseed until there are 256 bits added since the last extraction. This is problematic because (i) entropy estimation is impossible, but moreover (ii) a single malicious entropy source could be the source of all those credits. Usually a “scheduler” like Fortuna is added on top to mitigate this, but Linux doesn’t have that right now. The second mechanism is that we wait 5 minutes before reseeding automatically, and maybe this sort of papers over the former shortcoming. Maybe! Fingers-crossed, hands-waved, ….
2a) If you write into /dev/random, it actually won’t even credit your coinflip as having entropy. It’ll hash it into the pool, but won’t increment any counter. What you actually want there is
ioctl(devrandom_fd, RNDADDENTROPY, &(struct{int a,b;char c[32];}){256, 32, coin_flip...})
. That’ll dump those 32 bytes in and credit them for 256 bits. Alternatively you can write to /dev/random and then subsequently increment the entropy count (and hope that in between nothing extracts from the pool… there are a lot of related races like that everywhere) viaioctl(devrandom_fd, RNDADDTOENTCNT, 256)
.2b) None of this will reseed the crng immediately, though. You’ll have to wait til that 5 minute interval is up. Alternatively, you can force it to happen now via
ioctl(devrandom_fd, RNDRESEEDCRNG)
, which only does something if the pool has 256 bits of entropy counted since the last reseeding.Fair enough.
Yup. Already aware of that. Regardless, even though I don’t get the accounting credit for the reseed, the kernel should still be rekeyed, yes?
Doesn’t (2b) answer that? Or are you saying that you understood (2b), but think that behavior is bad and you want to change it?
Just making sure I understand 2b. Thanks.
Simplifying the above to answer your direct question: 2b says that the crng is not rekeyed immediately in response to you writing bytes into /dev/random. Rather, you need to wait for the entropy count to reach 256 bits (or set it yourself with one of those ioctls), and then wait 5 minutes or hit the reseed ioctl.
Thanks again.
I think the performance improvement might actually a great security feature in itself. It significantly lowers the chance that people feel the need to write their own user space rng and then inevitably get it very wrong.
Hey Jason, I know its off topic. But could not stop asking. Feel free to ignore. How did you draw the below flow(in the thread), Do you use any tool?
──extract()──► base_crng.key ◄──memcpy()───┐ │ │ └──chacha()──────┬─► new_base_key └─► crngs[n].key ◄──memcpy()───┐ │ │ └──chacha()───┬─► new_key └─► random_bytes │ └────►
It looks a lot like the output of asciflow to me.