12
$\begingroup$

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.

$\endgroup$
7
  • 2
    $\begingroup$ If you have one-time IKM from which one-time encryption and auth keys are derived with HKDF, my first thought as a protocol designer would be that it would be a waste of bandwidth/storage to pick a random nonce and store/send it when I could instead just use HKDF to derive it so that it never needs to be stored/sent. Or the nonce could just be set to zeroes. So then an additional question would be: does it really matter at all if the nonce is zero, if there is a one-time encryption key. $\endgroup$
    – knaccc
    Commented Aug 28, 2022 at 14:22
  • 1
    $\begingroup$ @knaccc That's been my thinking recently as well. With a large enough salt like PASETO/random keys, it's certainly fine. $\endgroup$ Commented Aug 28, 2022 at 15:44
  • 1
    $\begingroup$ @knaccc May I ask whether you'd risk it with a 128-bit random salt and potentially the same input (e.g. a password with a PBKDF)? $\endgroup$ Commented Aug 28, 2022 at 16:11
  • 2
    $\begingroup$ I'm not exactly sure what you are asking. I'd never dream of using zeroes as salt for PBKDF, due to the reduced-entropy nature of the IKM. My earlier comment was specifically about scenarios where there is one-time use IKM and therefore one-time use derived encryption/auth keys. Maybe you mean if it's a one-time use password? In that scenario, I think there is still an issue if the password is low-entropy that would necessitate the use of a salt. $\endgroup$
    – knaccc
    Commented Aug 28, 2022 at 17:19
  • 1
    $\begingroup$ I think the scenario you're proposing is: What if there is a protocol where the user enters a password to encrypt something, and where that password may be used on subsequent occasions to encrypt other data. A random 128-bit salt is generated and stored, the password and salt are used with PBKDF to derive a one-time encryption key, auth key and nonce, and then the file is encrypted. Your question is then: does it make a difference whether the nonce is randomly generated and stored, vs deterministically created and not stored? I don't think it changes the security of the scheme significantly. $\endgroup$
    – knaccc
    Commented Aug 29, 2022 at 0:11

3 Answers 3

14
$\begingroup$

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.

$\endgroup$
16
$\begingroup$

Nonces (and initialization vectors) are generally public. Assuming a sensible implementation (using a hash of the message as the nonce is not sensible), then no meaningful security is gained by making the nonce private.

Nonces are often simple counters that never repeat. For algorithms that accept large nonces (such as XChaCha20's 192-bit nonce), nonce-generation with a CSPRNG is also secure (and easier to manage).

In all likelihood, you're more likely to reduce security by implementing a home-baked scheme that derives the nonce by some other deterministic means. This advice may not seem intuitive, similar to how one may naively think that double-encryption increases security. My advice would be to use XChaCha20 and a public nonce generated by a decent CSPRNG.

$\endgroup$
3
  • $\begingroup$ I'm aware and agree that's not sensible. PASETO hashed the message and a random nonce, but they were concerned about RNG failure. Does it really have no security benefit though? With XChaCha20, the first 128 bits of the nonce are used for subkey derivation. If it's random (e.g. KDF derived), it's a bit like using a secret salt. As for implementation, it's basically a more complicated version of using a counter nonce. The main advantage of a separate random nonce over both approaches is that it's less likely to lead to nonce reuse. $\endgroup$ Commented Aug 28, 2022 at 13:33
  • 4
    $\begingroup$ It’s a question of “what do you gain?” vs “what could you lose?”. You gain 64+ secret bits that an attacker would have to brute-force. Considering that 256-bit keys are already considered to be far-beyond brute-forcable, you don’t really gain anything. In terms of what could you lose - by designing your own private-nonce scheme you lose the scrutiny of the thousands of academics and cryptographers who have spent years studying and vetting the scheme you’re modifying, which in turn may lead to subtle weaknesses that you’re unaware of. So in my opinion - the ends don’t justify the means. $\endgroup$
    – hunter
    Commented Aug 28, 2022 at 15:03
  • 4
    $\begingroup$ You don't even need to generate the nonce with a CSPRNG. Any PRNG which does not have short cycles is fine. $\endgroup$
    – forest
    Commented Aug 28, 2022 at 22:29
6
$\begingroup$

You can go back to the definition of the word. "Nonce" means "number once". It is a number with one and one feature only - that it is only used once. By definition and design, it should not be used in any manner which relies on it being secret. Algorithms will use it in places where it avoids replay attacks and similar things, i.e., attacks where you can repeat inputs to the algorithm without knowing the key.

To put it the other way 'round: if an algorithm requires the nonce to be secret, or if an algorithm becomes more secure if the nonce is kept secret, then by definition the nonce is not a nonce anymore, but part of the secret (i.e. the key).

Compare this to the general concept of differing the secret (i.e. the key) from anything else in cryptography. A good first benchmark for thinking about whether an algorithm is good is to verify that the key is literally the only thing that benefits from being secret, and assuming everything else (including nonces, salts etc.) can be public. Anything else would be either mislabeling, or just security by obscurity.

$\endgroup$
3
  • $\begingroup$ Yes, the nonce as a generic input shouldn't be considered secret. However, in these examples, it would be fine if the hidden nonce was revealed because it's independent from the key. The main motivation is that it saves you having to store a random nonce whilst being unpredictable to an attacker, unlike a counter starting at zero. It should have the same nonce reuse risk as a counter. $\endgroup$ Commented Aug 29, 2022 at 12:54
  • 2
    $\begingroup$ @samuel-lucas6, reading your question again seems like you have made your mind up anyways? My answer was simply to the one question that's actually there, "As the nonce is secret as well as the key from an attacker, how much security is likely gained from these types of approaches?" - my answer to that is "none". $\endgroup$
    – AnoE
    Commented Aug 29, 2022 at 13:19
  • $\begingroup$ Let me rephrase my previous response. I'm still debating what to do with my protocol. I want a counter nonce, but it's whether I bother having the initial value as random. It was before, but I wouldn't mind saving some storage/reading. This seems beneficial in some scenarios (e.g. that paper). However, I get that it's unnecessary from a security perspective. The key is enough; it just seems like this does no harm apart from being marginally more complicated than a counter nonce starting at 0. It feels similar to using a secret salt when one isn't needed. $\endgroup$ Commented Aug 29, 2022 at 15:12

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.