3 ms·
It's not just the initial seeding, you also need correct reseeding, you need to make sure the state doesn't leak somehow, and you need to make sure you're actua
by mmalone 11y ago
It's not just the initial seeding, you also need correct reseeding, you need to make sure the state doesn't leak somehow, and you need to make sure you're actually getting the seed data securely. If you're doing something that's crypto related there really are a lot of things you can screw up in user space. Using urandom directly is your best bet. It's not fake secure, it's just non-trivial to get right.
- Dylan16807 11y agoYou don't need to reseed. If the only access is a function that spits out a random number it's trivial to not let the state leak. If you can't figure out how to open urandom securely to get the seed data, how are you going to use urandom every time you need a number?
- mmalone 11y agoIncorrect. You may be thinking of the "/dev/random vs. /dev/urandom" argument, which says it's stupid to _block_ on reseeding based on some arbitrary heuristic (and which I agree with). However, that doesn't mean reseeding is unnecessary. Even a CSPRNG cycles and you need to reseed before it does so or the wheels start to come off. Generators become less random looking even before cycling. The general rule is that you shouldn't use more than sqrt(cycle length) from a single generator. If you use a secure n-bit block cipher in counter mode, for instance (generally considered a "good CSPRNG") then the generated numbers start to become distinguishable from random after 2^(n/2) generated blocks due to lack of collisions. This is a weak statement, but the point is any proofs that assume randomness (likely all proofs of hardness of crypto reversal) no longer hold. If you don't reseed before this point then you're doing it wrong. Other desirable characteristics of CSPRNGs, like forward secrecy, may require periodic (or frequent) reseeding depending on algorithm. Best practice for a source of secure "randomness" is to use an entropy accumulator that finds as much "true entropy" as it can and constantly mixes that into a pool (while protecting against injection attacks), then to use a good CSPRNG algorithm to "stretch" the available entropy since true entropy is a scarce resource. That's what urandom and OpenSSL do, for instance (see Yarrow/Fortuna for a good design). A lot of thought has been put into the design of urandom. Pulling one random seed from urandom and stretching it forever in user-space is _not_ equivalent. You could probably design something in user-space that _is_ as secure, but it's not trivial.
- Dylan16807 11y agoIf you're using 384 bits of state as with ChaCha20, you do not need to reseed for quality reasons. Adding in more is nice of the kernel but not necessary. If the pool doesn't already have enough entropy to last the lifetime of the computer, I would prefer not to trust it yet.
- mmalone 11y agoThe simpler design is probably to just fill a pool of entropy from urandom in user-space and give out numbers from that pool, thus amortizing the syscall overhead. Even that would be not-quite-as-good-as-urandom (still more that could go wrong), but it's probably as close as you can easily get.
- mmalone 11y agoOh, one more thought since I didn't really address state leak. Let's pretend we're in a C-like language that is not memory safe. You're not reseeding and you don't have forward secrecy. Someone finds a buffer overflow and manages to get your CSPRNG state. Now they can recover the sequence of randomness you've handed out in the past (maybe they're access tokens, for instance). It's not a trivial attack, but it's plausible. If you don't like the buffer overflow example, let's make it a misconfigured website that leaks the state in an error message or stack trace served to an end user.