Skip to main content
Added the XChaCha20 part to the beginning and addressed the OP's question more deeply.
Source Link
kelalaka
  • 49.5k
  • 12
  • 119
  • 205

First the XChaCha20-Poly1305 basics

  • Why one may need XChaCha20

    ChaCha20 is 20 round from the ChaCha family. The Bernstein version of ChaChax has a 64-bit nonce and 64 bit counter. Bernstein argued that this should be enough in the XSalsa paper

    There is a standard argument that a 64-bit nonce is long enough. Nonce security does not mean unpredictability; it means uniqueness. Applications can generate a nonce as a monotonic timestamp or simply a counter 1,2,3,...

    For long-lived keys, the 64-bit nonce of ChaCa20 is too short to use securely since with the birthday attack around the 2^32 messages one will have 50% of hitting the same random nonce that will at least result in the loss of the confidentiality.

    XChaCha20 is based on the IETF version that uses 96-bit nonces.

  • The security of ChaCha20-Poly1305 with random nonces

    The ietf' docs say that after around $2^{96}$ messages one should expect a collision with the birthday attack. 50% is very advantageous for the attacker and a more conservative one is generating at most $2^{80}$ nonce so that the collision probability is $\frac{1}{2^{32}}$. And, still, this $2^{80}$ message under one key should be enough for all. Therefore, the XChaCha20 is safe to use with random nonces. The security reduced to the security of the ChaCha20-Poly1305

  • How the ChaCha20-Poly1305 works

    • The 128-bit key and the first 128-bit (16-byte) of the uniform random nonce is processed with the HChaCha20
    • The HChaCha20 returns two 128 bits.
    • The remaining 64-bit ( 8-byte) of the nonce is appended with 4 null bytes.
      xchacha20_encrypt(key, nonce, plaintext, blk_ctr = 0):
           subkey = hchacha20(key, nonce[0:15])
           chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23]
      
           return chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
      

Back to Questions

There is no need forI'm reading this. The first part of the nonce is used to mix with the key and the second part left intact. like this

```
xchacha20_encrypt(key, nonce, plaintext, blk_ctr = 0):
     subkey = hchacha20(key, nonce[0:15])
     chacha20_noncesubNonce = "\x00\x00\x00\x00"hchacha20(key + nonce[0:15], nonce[16:23])
     chacha20_nonce = "\x00\x00\x00\x00" + subNonce
     return chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
```

To decrypt the other side must follow the same steps since they are not reversible! Therefore you need to send the nonce[16:23] as it is.

Therefore is no need for this since we expect that the nonce is generated uniform randomly. If you want to really do it, you can, you will get no advantage on the brute-force side. The attacker will still need to search over 128-bit. As a result, this adds nothing at all to the security.

There is no need to encryptIt doesn't compromise anything at all but also doesn't provide any at all in the noncesecurity of the XChaCha20-Poly1305. The nonce is already is random and remember the onlybrute-force attack, as mentioned above, will still need for a 128-bit key is the secretsearch.

There is no need for this. The first part of the nonce is used to mix with the key and the second part left intact.

xchacha20_encrypt(key, nonce, plaintext, blk_ctr = 0):
     subkey = hchacha20(key, nonce[0:15])
     chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23]

     return chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)

There is no need to encrypt the nonce. The nonce is already is random and remember the only key is the secret.

First the XChaCha20-Poly1305 basics

  • Why one may need XChaCha20

    ChaCha20 is 20 round from the ChaCha family. The Bernstein version of ChaChax has a 64-bit nonce and 64 bit counter. Bernstein argued that this should be enough in the XSalsa paper

    There is a standard argument that a 64-bit nonce is long enough. Nonce security does not mean unpredictability; it means uniqueness. Applications can generate a nonce as a monotonic timestamp or simply a counter 1,2,3,...

    For long-lived keys, the 64-bit nonce of ChaCa20 is too short to use securely since with the birthday attack around the 2^32 messages one will have 50% of hitting the same random nonce that will at least result in the loss of the confidentiality.

    XChaCha20 is based on the IETF version that uses 96-bit nonces.

  • The security of ChaCha20-Poly1305 with random nonces

    The ietf' docs say that after around $2^{96}$ messages one should expect a collision with the birthday attack. 50% is very advantageous for the attacker and a more conservative one is generating at most $2^{80}$ nonce so that the collision probability is $\frac{1}{2^{32}}$. And, still, this $2^{80}$ message under one key should be enough for all. Therefore, the XChaCha20 is safe to use with random nonces. The security reduced to the security of the ChaCha20-Poly1305

  • How the ChaCha20-Poly1305 works

    • The 128-bit key and the first 128-bit (16-byte) of the uniform random nonce is processed with the HChaCha20
    • The HChaCha20 returns two 128 bits.
    • The remaining 64-bit ( 8-byte) of the nonce is appended with 4 null bytes.
      xchacha20_encrypt(key, nonce, plaintext, blk_ctr = 0):
           subkey = hchacha20(key, nonce[0:15])
           chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23]
      
           return chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
      

Back to Questions

I'm reading this like this

```
xchacha20_encrypt(key, nonce, plaintext, blk_ctr = 0):
     subkey = hchacha20(key, nonce[0:15])
     subNonce = hchacha20(key + nonce[0:15], nonce[16:23])
     chacha20_nonce = "\x00\x00\x00\x00" + subNonce
     return chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
```

To decrypt the other side must follow the same steps since they are not reversible! Therefore you need to send the nonce[16:23] as it is.

Therefore is no need for this since we expect that the nonce is generated uniform randomly. If you want to really do it, you can, you will get no advantage on the brute-force side. The attacker will still need to search over 128-bit. As a result, this adds nothing at all to the security.

It doesn't compromise anything at all but also doesn't provide any at all in the security of the XChaCha20-Poly1305. The brute-force attack, as mentioned above, will still need for a 128-bit key search.

Source Link
kelalaka
  • 49.5k
  • 12
  • 119
  • 205

My question is could we encrypt the 2nd part of the nonce by running an additional initial round (HChaCha20) with the 16 bytes of the nonce and the key?

There is no need for this. The first part of the nonce is used to mix with the key and the second part left intact.

xchacha20_encrypt(key, nonce, plaintext, blk_ctr = 0):
     subkey = hchacha20(key, nonce[0:15])
     chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23]

     return chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)

I presume this would compromise something somewhere. It seems like a very simple and cheap way to make a brute force more difficult. The additional round(s) would take about 10ms.

There is no need to encrypt the nonce. The nonce is already is random and remember the only key is the secret.