arthrop0d

Brief articles on varied topics.

AEAD Nonces and the Cost of Reuse

cryptographycomputer security

An AEAD nonce is a value supplied to authenticated encryption that must be unique for each encryption performed with the same key. It is usually public, not a secret; its job is to ensure that each encryption gets a fresh internal starting point.

AEAD means authenticated encryption with associated data. It encrypts a plaintext so outsiders cannot read it, while also producing an authentication tag that lets the recipient detect changes. It can authenticate data that remains visible—such as a protocol version, message type or header—without encrypting that data.

The nonce is the part that makes repeated use of one key safe across many messages. Reusing it with that key can break both the confidentiality and the authenticity that AEAD is intended to provide.

The problem AEAD solves

Plain encryption addresses only secrecy. If an attacker can alter encrypted bytes and the recipient has no way to detect the alteration, the attacker may be able to change a command, amount or permission in transit. Encryption also does not automatically prevent an attacker from rearranging, deleting or replaying messages.

A separate message authentication code can detect tampering, but combining encryption and authentication correctly is subtle. The encryption and authentication must cover the right fields, use the right order, and avoid accidental key or nonce reuse. AEAD packages the combination into one defined operation:

The associated data is authenticated but not encrypted. For example, a protocol might leave a message type visible to routers while ensuring that changing the type causes verification to fail.

You have probably met the nonce in an API parameter or a configuration error such as “nonce must be 12 bytes” or “counter reuse detected.” In protocols, it may appear as an explicit field next to the ciphertext, or it may be constructed from a packet number and a fixed connection value.

How the nonce participates in encryption

Many AEAD schemes generate a stream of pseudorandom bytes from the key and nonce. “Pseudorandom” here means that the bytes look random to someone who does not know the key. The plaintext is combined with that stream to produce the ciphertext.

Conceptually, for a plaintext P, ciphertext C, and keystream S:

C = P XOR S
P = C XOR S

XOR combines bits so that applying the same operation twice reverses it. The nonce makes S different for each message, even when the key stays the same.

AEAD also computes a tag over the ciphertext and associated data, using the key and nonce as part of that calculation. The recipient recomputes and checks the tag before returning plaintext. A failed check must be treated as a failed decryption—not as a request to continue with possibly modified data.

AES-GCM and ChaCha20-Poly1305 are widely used examples. Their internal constructions differ, but both depend on the same operational rule: never repeat a nonce with the same key.

What goes wrong when a nonce repeats

Suppose two messages use the same key and nonce. If the scheme derives the same keystream S for both, then:

C1 = P1 XOR S
C2 = P2 XOR S
C1 XOR C2 = P1 XOR P2

The keystream cancels out. An attacker does not immediately get both plaintexts from P1 XOR P2, but this is still a serious leak. If one plaintext is known or can be guessed—for example, a predictable protocol header—the attacker can recover the corresponding keystream and decrypt the other message wherever it overlaps. Even without a fully known plaintext, the relationship between the two plaintexts often reveals structure and permits targeted recovery.

The tag is affected too. AEAD authentication is not an independent shield against nonce reuse. In AES-GCM, for example, the repeated nonce causes the same internal authentication values to be used in multiple tag calculations. Observing tags for messages under the same nonce gives an attacker equations involving secret authentication material. Depending on what the attacker can observe or choose, that can lead to tags being forged for modified or entirely new ciphertexts.

ChaCha20-Poly1305 has the same basic confidentiality failure because the ChaCha20 stream repeats. Its authentication component also relies on a one-time value derived for that nonce; using the nonce again violates that one-time assumption and can make forgery possible. The exact attack and amount of information exposed depend on the construction and available messages, but “the tag will catch it” is not a safe assumption.

A nonce does not need to be secret. It does need to be unique for the lifetime of its key.

Making uniqueness reliable

A counter is often the clearest design: start at zero and increment for every message encrypted under the key. The counter must not wrap, and its state must survive process restarts. If two processes share a key, they must coordinate their counter ranges rather than each starting at zero.

Random nonces can work when the nonce is large enough and collisions are acceptably unlikely. They are not automatically safe: a random choice can repeat, and the risk grows as more messages are encrypted. Libraries and protocols commonly choose a nonce size specifically to make accidental collisions negligible, but the application still needs to follow the scheme’s requirements.

Key rotation can limit how many messages share a key, but it does not make nonce reuse acceptable within a key. A robust design specifies who allocates nonces, how state is persisted, what happens after a crash or rollback, and how a distributed system avoids duplicate allocation.

Treat nonce reuse as a security incident, not merely a decryption error. Stop using the affected key, determine which messages may have shared a nonce, and rotate the key. Once a nonce has been reused, the confidentiality and authenticity guarantees for that key can no longer be assumed.

← All articles