On Fri, Jun 10, 2016 at 05:14:50PM -0400, Random832 wrote:
On Fri, Jun 10, 2016, at 15:54, Theodore Ts'o wrote:
So even on Python pre-3.5.0, realistically speaking, the "weakness" of os.random would only be an issue (a) if it is run within the first few seconds of boot, and (b) os.random is used to directly generate a long-term cryptographic secret. If you are fork openssl or ssh-keygen to generate a public/private keypair, then you aren't using os.random.
So, I have a question. If this "weakness" in /dev/urandom is so unimportant to 99% of situations... why isn't there a flag that can be passed to getrandom() to allow the same behavior?
The intention behind getrandom() is that it is intended *only* for cryptographic purposes. For that use case, there's no point having a "return a potentially unseeded cryptographic secret" option. This makes this much like FreeBSD's /dev/random and getentropy system calls. (BTW, I've seen an assertion on this thread that FreeBSD's getentropy(2) never blocks. As far as I know, this is **not** true. FreeBSD's getentropy(2) works like its /dev/random device, in that if it is not fully seeded, it will block. The only reason why OpenBSD's getentropy(2) and /dev/random devices will never block is because they only support architectures where they can make sure that entropy is passed from a previous boot session to the next, given specialized bootloader support. Linux can't do this because we support a very large number of bootloaders, and the bootloaders are not under the kernel developers' control. Fundamentally, you can't guarantee both (a) that your RNG will never block, and (b) will always be of high cryptographic quality, in a completely general sense. You can if you make caveats about your hardware or when the code runs, but that's fundamentally the problem with the documentation of os.urandom(); it's making promises which can't be true 100% of the time, for all hardware, operating environments, etc.) Anyway, if you don't need cryptographic guarantees, you don't need getrandom(2) or getentropy(2); something like this will do just fine: long getrand() { static int initialized = 0; struct timeval tv; if (!initialized) { gettimeofday(&tv, NULL); srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); initialized++; } return random(); } So this is why I did what I did. If Python decides to go down this same path, you could define a new interface ala getrandom(2), which is specifically designed for cryptogaphic purposes, and perhaps a new, more efficient interface for those people who don't need cryptogaphic guarantees --- and then keep the behavior of os.urandom consistent with Python 3.4, but update the documentation to reflect the reality. Alternatively, you could keep the implementation of os.urandom consistent with Python 3.5, and then document that under some circumstances, it will block. Both approaches have certain tradeoffs, but it's not going to be the end of the world regardless of which way you decide to go. I'd suggest that you use your existing mechanisms to decide on which approach is more Pythony, and then make sure you communicate and over-communicate it to your user/developer base. And then --- relax. It may seem like a big deal today, but in a year or so people will have gotten used to whatever interface or documentation changes you decide to make, and it will be all fine. As Dame Julian of Norwich once said, "All shall be well, and all shall be well, and all manner of things shall be well." Cheers, - Ted