What breaks when you reuse an AEAD nonce: AES-GCM vs ChaCha20-Poly1305

What reusing a nonce under one key costs you in AES-GCM and in ChaCha20-Poly1305, and how to build nonces that never repeat, per RFC 5116 and RFC 8439.

cryptographyaeadaes-gcmchacha20-poly1305nonce

When you encrypt with the AES-GCM algorithms registered in RFC 5116 (AEAD_AES_128_GCM, AEAD_AES_256_GCM) or with RFC 8439’s ChaCha20-Poly1305, you pass a 12-byte nonce along with the key. The nonce can be stored right next to the ciphertext or sent with it. There is one rule to keep: never use the same nonce twice when encrypting under the same key. What you lose when that rule breaks depends on the algorithm, and AES-GCM pays an especially high price.

This post is based on RFC 5116 (2008), which defines the AEAD interface and the AES-GCM and AES-CCM algorithms, and RFC 8439 (2018), which defines ChaCha20-Poly1305 and obsoletes RFC 7539. Both were checked on 2026-10-12. NIST SP 800-38D, the specification of GCM itself, was not used as a source here, so topics such as the limits on generating GCM nonces (IVs) at random are out of scope.

What the AEAD interface requires

In RFC 5116 §2.1, authenticated encryption takes four inputs: a secret key K, a nonce N, a plaintext P, and associated data A, which is authenticated but not encrypted. The nonce requirements are:

  • For any given key value, the nonces passed to distinct encryption calls MUST all be different. The only exception is when every nonce used with that key has length zero.
  • The length SHOULD be 12 octets (bytes).
  • The nonce may be stored or sent with the ciphertext, or rebuilt just before decryption from context such as message order. It is authenticated inside the algorithm, so there is no need to add it to A.

The zero-length exception does not apply to AES-GCM or ChaCha20-Poly1305. It exists for randomized or stateful algorithms (§3, §4), while AEAD_AES_128_GCM and AEAD_AES_256_GCM in RFC 5116 and AEAD_CHACHA20_POLY1305 in RFC 8439 all have a minimum and maximum nonce length (N_MIN, N_MAX) of 12 octets.

The key point is that RFC 5116’s common interface does not define a single outcome for “what happens if nonces collide.” Section 4 asks each algorithm specification to describe (SHOULD) how security degrades if a nonce is accidentally reused. So the consequences have to be read per algorithm.

AES-GCM: confidentiality of two messages, and all authentication under that key

RFC 5116 §5.1.1 says that if GCM encrypts two different plaintexts with the same key and the same nonce, two things fall apart.

  1. Confidentiality. An attacker who sees both ciphertexts can reconstruct the XOR of the two plaintexts.
  2. Integrity. The attacker can recover GCM’s internal hash key used for integrity protection, and knowing that key makes subsequent forgeries trivial.

The second item is what makes GCM especially dangerous. The confidentiality loss is limited to the two messages that shared a nonce, but on the authentication side, in the RFC’s words, “all of the authenticity and integrity protection provided by that key” is undermined. A valid tag under that key no longer shows that a message is genuine. So if you find nonce reuse under GCM, avoiding that nonce from now on is not enough; you need to replace the key. That conclusion is drawn from the text of §5.1.1. The RFC does not prescribe a key replacement procedure.

The same section says GCM should only be used when nonce uniqueness can be provided with assurance, and attributes the weakness to the design feature GCM uses to achieve minimal latency. It also notes that the serious consequences above do not apply if both the plaintext and the associated data were identical in the two encryptions. That exception covers only the case where the two calls had exactly the same input, so don’t read it as permission to reuse.

ChaCha20-Poly1305: the keystream and the one-time key repeat

RFC 8439 §4 calls the uniqueness of the nonce used in ChaCha20 the most important security consideration in implementing the document. If a nonce repeats, the keystream and the one-time Poly1305 key are identical between the two messages. With the same keystream, the XOR of the two ciphertexts equals the XOR of the two plaintexts, so the plaintext XOR is exposed.

In the AEAD construction (§2.8), a fresh one-time Poly1305 key is derived for each message from the key and nonce (§2.6). Poly1305 is, as the name says, a one-time authenticator, and §2.5 requires that its key pair (r, s) should be unique and MUST be unpredictable for each invocation. Reusing the nonce makes that key pair the same for both messages, which breaks the premise.

RFC 8439 does not, however, say that a long-lived authentication key can be recovered the way it does for GCM, nor does it spell out how far forgery can go in this case. So don’t read it as “ChaCha20-Poly1305 keeps authentication safe under nonce reuse,” and don’t transplant GCM’s key-recovery description onto it either. What the RFC states is that the keystream and the one-time key become identical and the plaintext XOR is exposed.

For comparison, RFC 5116 §5.3.1 gives the consequence of nonce reuse in AES-CCM as a loss of confidentiality, with the XOR of the two plaintexts exposed.

Algorithm Source Stated consequence of nonce reuse
AES-GCM RFC 5116 §5.1.1 XOR of the two plaintexts exposed; internal hash key recovered, undermining all authentication under that key
ChaCha20-Poly1305 RFC 8439 §4 Keystream and one-time Poly1305 key identical; XOR of the two plaintexts exposed
AES-CCM RFC 5116 §5.3.1 XOR of the two plaintexts exposed

Building nonces that don’t collide

The format recommended by RFC 5116 §3.2 is a Fixed field at the front followed by a Counter field. Implementations SHOULD support a 12-octet nonce with a 4-octet counter. RFC 8439 §2.3 gives an example for several senders sharing one key: make the first 32 bits unique per sender and fill the remaining 64 bits from a counter. The split between the two fields differs, but the shape is the same.

RFC 5116 §3.2 (12-octet nonce, 4-octet counter)
+--------------------------------+----------------+
|        Fixed (8 octets)        |  Counter (4)   |
+--------------------------------+----------------+

RFC 8439 §2.3 (multiple senders sharing one key)
+----------------+--------------------------------+
|   Sender (4)   |      Counter (8 octets)        |
+----------------+--------------------------------+

RFC 5116 describes the format this way:

  • In the recommended format, the Counter fields of successive nonces form a monotonically increasing sequence when read as unsigned integers in network byte order. The counter SHOULD start at 0 and go up by 1 each time, and a value MAY be skipped when convenient.
  • A C-octet counter yields at most 2^(8C) nonces, so 2^32 for 4 octets. Wrapping the counter back to 0 would bring back nonces already used, so the key has to change before the counter runs out.
  • The Fixed field must stay constant within one encryption device, and if several devices use one key, each MUST use a distinct Fixed field. An F-octet Fixed field allows at most 2^(8F) devices to share a key.

RFC 8439 leans toward counters as well. Section 2.6 says the nonce used for Poly1305 key generation must be unique per invocation with the same key, so it MUST NOT be randomly generated, and names a counter as a good way to implement this, with an LFSR (linear feedback shift register) also acceptable. Section 4 adds that encrypting a counter with a 64-bit block cipher is acceptable, but truncating a counter encrypted with a 128-bit or 256-bit block cipher is not, because the truncated value may repeat after a short time.

When the counter rewinds

A counter scheme is weakest at the moment it loses its state. RFC 5116 points to these situations directly.

  • Several devices or instances share a key. They must coordinate so their nonces stay unique (§3.1). A distinct Fixed field per device is a simple way to do it.
  • A key lives across reboots. A counter held only in memory can start over after a reboot. Section 3.1 says to checkpoint the nonce in non-volatile storage, and explains that waiting for confirmation that the next value has been stored before encrypting gives high assurance against reuse. Since waiting every time adds latency, it also suggests storing a value several steps ahead: store 100, use 1 through 99, and store 200 in the meantime.
  • A virtual machine is rolled back to an earlier state. Section 8 warns that a software implementation in a VM could inadvertently reuse a nonce after such a rollback.

Section 3.1 also advises that where nonce coordination is difficult, many reuse problems can be avoided by changing the key.

Decryption needs its own note. RFC 5116 §5.1.1 says it is acceptable to input the same nonce value to the GCM decryption operation multiple times, but that sentence sits in the GCM section; it is not written as a rule of the common interface. At the interface level, §2.1 explains that if a nonce is reconstructed incorrectly and fed into authenticated decryption, the decryption detects it, so no security failure results. The uniqueness requirement RFC 5116 places on every AEAD is a rule about encryption calls. All of this concerns the cryptographic operation only. Section 1 says the AEAD interface does not address protocol issues such as anti-replay. Stopping an attacker from resending a valid ciphertext is the protocol’s job, so don’t read any of this as saying repeated decryption is harmless.

What to check

  • Count how many places generate nonces under one key. If there is more than one, confirm the space is split with a Fixed or sender field.
  • Find where the counter is stored. If it lives only in memory, confirm it does not restart from 0 after a restart, a snapshot restore, or a VM rollback.
  • Confirm the key is replaced before the counter limit (2^32 for 4 octets) is reached.
  • If reuse has actually happened under AES-GCM, treat that key as no longer trustworthy for authentication and replace it.

Sources

All checked on 2026-10-12.

Back to the blog