
[Nick Coghlan]
PEP: 522 Title: Allow BlockingIOError in security sensitive APIs on Linux ... Other than for ``random.SystemRandom`` (which is a relatively thin wrapper around ``os.urandom``), the ``random`` module has never made any guarantees that the numbers it generates are suitable for use in security sensitive operations,
To the contrary, it explicitly says it "should not be used for security purposes".
so the use of the system random number generator to seed the default Mersenne Twister instance is mainly beneficial as a harm mitigation measure for code that is using the ``random`` module inappropriately.
Except that's largely accidental. It so happens that using urandom() left Python immune to the "poor seeding" attacks in the PHP paper widely discussed when `secrets` was gestating, and it's entirely accidental that Python 3 (but not Python 2) happens to implement random.choice(), .randrange(), etc in such a way as to leave it resistant even to the PHP paper's "deduce MT state from partial outputs" attacks. Even wholly naive "generate a password" snippets using small alphabets with random.choice() are highly resistant to state-deducing attacks in Python 3. Those continue to be worth something. But the _real_ reason MT uses urandom() is that MT has massive internal state, and initialization wants the best chance it can get at picking any of the 2**19937-1 possible initial states. For example, seeding with time.time() and/or pid can't possibly get at more than an infinitesimal fraction of those. This has nothing to do with "security" - it has to do with best practice for simulations. Seeding the Twister (any PRNG with massive state) "fairly" is a puzzle, and seeding from urandom() was the best that could be done. Quite possible that, e.g., the system CSPRNG has only 512 bits of state, but that's still far better than brewing pseudo-nonsense out of a comparative handful of time.time() (etc) bits.
Since a single call to ``os.urandom()`` is cheap once the system random number generator has been initialized it makes sense to retain that as the default behaviour, but there's no need to issue a warning when falling back to a potentially more predictable alternative when necessary (in such cases, a warning will typically already have been issued as part of interpreter startup, as the only way for the call when importing the random module to fail without the implicit call during interpreter startup also failing if for the latter to have been skipped by entirely disabling the hash randomization mechanism).
Since the set of people who start simulations very early in the boot sequence is empty, I have no objection to any change here - so long as MT initialization continues using the OS RNG when possible.