encryption key-derivation authenticated-encryption nonce
Updated Tue, 27 Sep 2022 22:42:09 GMT

How much security is gained from hiding the nonce?

Public nonces can be problematic for privacy when they can be considered metadata. They can also be troublesome for security if you do things like using a hash of the message as the nonce.

PASETO now derives the nonce alongside the key using HKDF on the input keying material with a 256-bit salt. Thus, the actual nonce passed to AES-CTR and XChaCha is not revealed publicly.

The nonce used by AES-256-CTR and XChaCha20 will be derived from the HKDF output (which is now 48 bytes for v3.local and 56 bytes for v4.local). The first 32 bytes of each HKDF output will be used as the key. The remaining bytes will be used as the nonce for the underlying cipher.

TripleSec, an overkill multiple encryption library by Keybase, encrypts inner nonces.

The TripleSec technique takes one futher step not suggested by Schneier, which is to protect the inner IVs with the outer encryption algorithms, and only exposing the outermost IV in the clear. Though we can't prove this makes the scheme more secure, it seems like a reasonable idea: why reveal cipher inputs if we don't have to?

As the nonce is secret as well as the key from an attacker, how much security is likely gained from these types of approaches? Would it still be meaningfully beneficial with small nonces (e.g. 64 and 96 bits)?

I assume this is quite good with XChaCha20 due to the subkey derivation.


Hiding the nonce provides no tangible benefit. In the case of ChaCha where the input block is the concatenation of a constant, the key, a nonce, and a counter, using a random and secret nonce could be thought of as extending the key and reducing the size of the nonce. For IETF ChaCha with a 256-bit key, a 96-bit nonce and 32-bit counter, you could effectively turn it into a cipher with a 352-bit key and a 32-bit counter. Sure, this does increase the keyspace which technically improves security, but there's no need to do that as 256 bits is plenty. It works a little differently with block ciphers.

Interestingly, the Linux kernel's random driver uses a secret nonce (and secret counter) to initialize ChaCha20 as its CSPRNG. It uses random a 64-bit counter and nonce, so the key is effectively 320 bits (although the kernel only reseeds the 256-bit key). This is not done explicitly to improve security, but because it's easier to initialize the entire ChaCha input block with a constant and random data.

I have to echo what others have said though and warn you that going out of your way to hide the nonce is probably a bad idea! If your design is such that the nonce is naturally secret, then there's no reason to make it public, but there's also no reason to try to design a system where it must be secret.

My advice: If it would take more work to make the nonce public, then keep it secret. If it would take more work to make it secret, then keep it public. There's no need to complicate things.