OpenSSH uses a slightly different ChaCha20Poly1305 AEAD construct then the one proposed by A. Langley and others for TLS.

The TLS version

The openSSH version (and here)

  1. The openSSH version uses two 256bit keys.

  2. First key is used for deriving the Poly1305 MAC key and for encrypting the actual payload

  3. The second key is used to encrypt the AAD (the 4 byte packet length in the openSSH case)

  4. This construct result in at least 3 rounds of ChaCha20 for small messages (<=64 bytes).

  5. The first ChaCha20 round for deriving the 256bit Poly1305 key spits out 64bytes where the last 32bytes are unused.

  6. The second ChaCha20 round encrypts the AAD data (a 4 byte packet length)

  7. The third (and more) ChaCha20 round(s) encrypts the actual packet payload.

For small messages, this seems to generate an unnecessary overhead of up to 33% computation time (in case message payload is less then 64 bytes).

The question

  1. Why not use the unused 32bytes from the Poly1305 key derivation ChaCha20 round in order to encrypt the packet length (or say the AAD data up to 32 bytes)?

  2. Is it cryptographically required to use a 2nd ChaCha20 context with a 2nd key to encrypt the packet length (the AAD data),... or in other words, is it more secure to use a 2nd key (that very likely comes from the same single shared secret as the first key) rather then use a single key and encrypt the AAD data from the same ChaCha20 round that derived the Poly1305 key?


1 Answer 1


The point of having two ChaCha instances is to make sure that one cannot be used to attack the other. From the draft RFC:

Two separate cipher instances are used here so as to keep the packet lengths confidential but not create an oracle for the packet payload cipher by decrypting and using the packet length prior to checking the MAC.

Using the unused part of the first block from the same cipher instance as used for the rest of the construction would not seem to allow any kind of attack in this case, because that would always be the same part of the keystream, which is never used for anything else. I guess the proof of independence is easier with two cipher instances, but I suspect it is more about simplicity and extensibility.

By having a separate instance, you can easily decrypt the packet length separately using normal cipher interfaces, without adding any offsets. And by treating the encrypted packet length as additional data for the MAC, you get to use the normal process of verifying the MAC, without needing to decrypt it.

This way is also more extensible if there is a need for more than 32 bytes of additional data. It seems from the author's blog post there are some plans to extend this protection of packet lengths. Maybe that will require more additional data to be outside the main packet to allow earlier processing:

We're not done yet though - an attacker may still observe the encrypted packets on the network to try to ascertain their length, and right now they are likely to be successful. I hope to add some features to frustrate this sort of traffic analysis some time next year.

I.e. to answer your question explicitly, no, I do not think it is more secure to have a second cipher instead of using the unused 32 bytes. It seems there may just be other practical reasons to do that.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.