[Python-Dev] BDFL ruling request: should we block forever waiting for high-quality random bits?

Cory Benfield cory at lukasa.co.uk
Thu Jun 16 07:58:29 EDT 2016

> On 16 Jun 2016, at 09:19, Stefan Krah <stefan at bytereef.org> wrote:
> This should only concern code that a) was specifically written for
> 3.5.0/3.5.1 and b) implements a serious cryptographic application
> in Python.
> I think b) is not a good idea anyway due to timing and side channel
> attacks and the lack of secure wiping of memory. Such applications
> should be written in C, where one does not have to predict the
> behavior of multiple layers of abstractions.

No, it concerns code that generates its random numbers from Python. For example, you may want to use AES GCM to encrypt a file at rest. AES GCM requires the use of an nonce, and has only one rule about this nonce: you MUST NOT, under any circumstances, re-use an nonce/key combination. If you do, AES GCM fails catastrophically (I cannot emphasise this enough, re-using a nonce/key combination in AES GCM totally destroys all the properties the algorithm provides)[0].

You can use a C implementation of all of the AES logic, including offload to your x86 CPU with its fancy AES GCM instruction set. However, you *need* to provide an nonce: AES GCM can’t magically guess what it is, and it needs to be communicated in some way for the decryption[1]. In situations where you do not have an easily available nonce (you do have it for TLS, for example), you will need to provide one, and the logical and obvious thing to do is to use a random number. Your Python application needs to obtain that random number, and the safest way to do it is via os.urandom().

This is the problem with this argument: we cannot wave our hands and say “os.urandom can be as unsafe as we want because crypto code must not be written in Python”. Even if we never implement an algorithm in Python (and I agree with you that crypto primitives in general should not be implemented in Python for the exact reasons you suggest), most algorithms require the ability to be provided with good random numbers by their callers. As long as crypto algorithms require good nonces, Python needs access to a secure CSPRNG. Kernel CSPRNGs are *strongly* favoured for many reasons that I won’t go into here, so os.urandom is our winner.

python-dev cannot wash its hands of the security decision here. As I’ve said many times, I’m pleased to see the decision makers have not done that: while I don’t agree with their decision, I totally respect that it was theirs to make, and they made it with all of the facts.


[0]: Someone will *inevitably* point out that other algorithms resist nonce misuse somewhat better than this. While that’s true, it’s a) not relevant, because some standards require use of the non-NMR algorithms, and b) unhelpful, because even if we could switch, we’d need access to the better primitives, which we don’t have.

[1]: Again, to head off some questions at the pass: the reason nonces are usually provided by the user of the algorithm is that sometimes they’re generated semi-deterministically. For example, TLS generates a unique key for each session (again, requiring randomness, but that’s neither here nor there), and so TLS can use deterministic *but non-repeated* nonces, which in practice it derives from record numbers. Because you have two options (re-use keys with random nonces, or random keys with deterministic nonces), a generic algorithm implementation does not constrain your choice of nonce.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://mail.python.org/pipermail/python-dev/attachments/20160616/8b921c37/attachment.sig>

More information about the Python-Dev mailing list