AES-GCM and ChaCha20-Poly1305 are both sound authenticated ciphers, so the real decision is about hardware, nonce discipline, key volume limits and compliance scope, and getting those wrong matters far more than the algorithm name. They differ in where they are fast, how much data a key can safely protect, how they behave in software on small devices, and which standards bodies specify them. This guide is for architects, platform engineers and reviewers choosing a cipher for services, VPNs, mobile apps and device fleets. It assumes the AEAD basics in the Authenticated Encryption and Block Cipher Modes Guide and goes deeper on the choice between the two.
Key takeaways
- Hardware decides speed. With AES instructions, AES-GCM is usually faster; without them, RFC 8439 says ChaCha20 is roughly three times as fast in software and avoids table-based cache-timing leaks.
- ChaCha20-Poly1305 tolerates more data per key. RFC 8446 caps AES-GCM at 2^24.5 full-size records per TLS connection, while for ChaCha20-Poly1305 the sequence number wraps first; QUIC sets 2^23 packets for AES-GCM and no practical confidentiality limit for ChaCha20-Poly1305.
- Nonce reuse is catastrophic for both. Neither is nonce misuse resistant; reuse leaks plaintext XOR and, for GCM, enables forgery. Use protocol-built nonces or counters, never ad hoc random IVs at volume.
- Compliance can settle it for you. AES-GCM is a NIST mode (SP 800-38D) and the only mandatory TLS 1.3 suite; ChaCha20-Poly1305 is an IRTF specification (RFC 8439), so FIPS 140-3 scopes must confirm module coverage.
- Offer both, let negotiation choose. Most public services should enable both in TLS 1.3; fixed-cipher systems (WireGuard) and constrained IoT stacks (AES-CCM, Ascon) are the exceptions.
The short answer
Use AES-GCM (AES-128-GCM or AES-256-GCM) on servers, cloud services and any platform with AES hardware instructions, and wherever a FIPS 140-3 validated module or a NIST-specified mode is required. Use ChaCha20-Poly1305 where clients lack AES acceleration (older or low-end mobile and embedded CPUs), where constant-time software implementations matter more than peak throughput, and where very long-lived keys would otherwise run into GCM's volume limits. For a public TLS 1.3 endpoint, enable both and let the handshake pick. For a closed system where you control both ends, pick one, document why, and design nonce handling and rekeying around its limits.
Side by side
| Dimension | AES-GCM | ChaCha20-Poly1305 |
|---|---|---|
| Specification | NIST SP 800-38D (Final, 2007; NIST decided on 6 March 2024 to revise it); RFC 5116 AEAD identifiers | RFC 8439 (Informational, IRTF CFRG consensus, June 2018, obsoletes RFC 7539) |
| Construction | AES in counter mode plus GHASH, a polynomial MAC over GF(2^128) | ChaCha20 stream cipher (add, rotate, XOR) plus Poly1305 one-time MAC |
| Key / nonce / tag | 128 or 256-bit key, 96-bit nonce, 128-bit tag | 256-bit key, 96-bit nonce, 128-bit tag |
| Fastest on | CPUs with AES and carry-less multiply instructions | CPUs without AES hardware; RFC 8439 cites about three times AES speed in software |
| Side channels in software | Table-based AES is exposed to cache-timing attacks; hardware AES or bitsliced code avoids this | No key-dependent table lookups, so constant time by construction when implemented as specified |
| TLS 1.3 status (RFC 8446 s.9.1) | TLS_AES_128_GCM_SHA256 is MUST; TLS_AES_256_GCM_SHA384 is SHOULD | TLS_CHACHA20_POLY1305_SHA256 is SHOULD |
| Per-connection volume (TLS 1.3) | 2^24.5 full-size records, then KeyUpdate | Sequence number wraps before the safety limit |
| Single message size | 2^36 minus 31 octets (RFC 5116) | About 256 GB per key and nonce (2^32 blocks) |
Hardware acceleration and performance
Performance claims about these ciphers are almost always claims about the CPU. AES is a block cipher built around lookup tables; done in plain software it is slow and, if implemented with key-dependent tables, leaks timing through the cache. Modern x86 server and desktop processors (AES-NI with carry-less multiply) and ARMv8 cores with the Cryptography Extensions execute AES rounds and the GHASH multiply in hardware, which makes AES-GCM very fast and constant time. RFC 8439's own benchmark appendix shows the effect: on a Sandy Bridge Xeon with AES-NI it reports about 900 MB/s for AES-128-GCM against about 500 MB/s for ChaCha20-Poly1305.
Remove the hardware and the picture inverts. ChaCha20 uses only 32-bit additions, XORs and fixed rotations, which every CPU does quickly, so RFC 8439 describes it as considerably faster than AES in software-only implementations, roughly three times as fast. That is why it was adopted for mobile TLS and is the only cipher in WireGuard.
- Measure on the real client mix: server CPUs with AES instructions are near universal, so the question is usually the client side: budget phones, set-top boxes, microcontrollers and older ARM cores.
- Battery and heat count: on devices without AES hardware, ChaCha20-Poly1305 uses fewer cycles per byte, which matters for battery-powered fleets.
- Do not hand-roll AES in software: if you must run AES without hardware support, use a library's constant-time (bitsliced or vector permute) implementation, not a textbook T-table version.
Nonce misuse: the shared weakness
Both ciphers require a nonce that never repeats under the same key. Neither tolerates reuse, but the damage differs in detail.
- ChaCha20-Poly1305: RFC 8439 states that reusing a nonce with the same key repeats both the keystream and the one-time Poly1305 key, which reveals the XOR of the plaintexts and undermines the authenticator.
- AES-GCM: reuse likewise repeats the CTR keystream, and two messages under one nonce let an attacker recover the GHASH authentication key, after which they can forge valid ciphertexts under that key and nonce. GCM's failure is therefore an integrity failure as well as a confidentiality one, which is why the AE guide calls nonce uniqueness the whole contract.
How nonces should be produced
| Context | Nonce source | Your responsibility |
|---|---|---|
| TLS 1.3 records (RFC 8446 s.5.3) | 64-bit record sequence number, padded and XORed with a per-direction static write IV; resets to 0 on each new traffic key | Use a maintained TLS library; never reimplement record protection |
| QUIC (RFC 9001) | Packet number combined with the packet protection IV | Enforce the key update and limits in the library configuration |
| WireGuard | 32 zero bits plus a 64-bit little-endian counter that cannot go backwards; receivers keep a replay window | Nothing to configure; keep the implementation patched |
| Application or field encryption | Counter per key, or random 96-bit nonce within limits | Persist counters across restarts and snapshots; cap random-nonce messages per key; prefer per-message or per-writer keys |
| Many stateless writers sharing a key | Random nonces collide eventually | Derive a key per writer, use a larger-nonce variant, or a misuse-resistant AEAD such as AES-GCM-SIV (RFC 8452) |
XChaCha20-Poly1305 extends the nonce to 192 bits using HChaCha20 so random nonces are safe at far higher volume. It is widely implemented in libraries, and WireGuard uses it with a random 24-byte nonce for its cookie messages, but its specification, draft-irtf-cfrg-xchacha-03, is an expired IRTF draft with no formal standing (checked November 2026). Use it through a mature library and do not cite it as a standard in compliance documents.
Key wear-out and usage limits
Every AEAD has a limit on how much data one key can protect before an attacker's advantage grows past an acceptable bound. This is where the two ciphers differ most, and where protocol designers have done the work for you.
| Source | AES-GCM | ChaCha20-Poly1305 |
|---|---|---|
| RFC 8446 s.5.5 (TLS 1.3) | Up to 2^24.5 full-size records (about 24 million) per connection; perform KeyUpdate before the limit | The record sequence number would wrap before the safety limit |
| RFC 9325 (BCP 195) | Recommends the same 2^24.5 record limit for TLS 1.2 and 1.3; DTLS 1.2 integrity limit 2^28 failed records | No separate figure given |
| RFC 9001 s.6.6 (QUIC), confidentiality | 2^23 packets per key | Greater than the number of possible packets (2^62) |
| RFC 9001 s.6.6 (QUIC), integrity | 2^52 failed packets per connection | 2^36 failed packets per connection |
| draft-irtf-cfrg-aead-limits-13 (Informational draft, 3 September 2026) | Single-key limits on both confidentiality and integrity; multi-key limits shrink as blocks per key grow | No single-key confidentiality limit beyond the ChaCha20 PRF; integrity limited by forgery attempts |
Two practical consequences follow. First, AES-GCM keys in long-lived or high-volume channels (bulk replication links, persistent tunnels, message buses) must be rotated by count, not only by time; TLS 1.3 handles this with the KeyUpdate message (RFC 8446 s.4.6.3), but home-grown protocols often forget. Second, ChaCha20-Poly1305 has a notably lower integrity limit than AES-GCM in QUIC, so endpoints must count authentication failures and close the connection with AEAD_LIMIT_REACHED, as RFC 9001 requires for both. The CFRG draft warns that single-key limits must not be applied where many keys are deployed, and it is still a draft, so treat its numbers as guidance.
For storage, note the per-message ceilings: RFC 8439 says the 32-bit block counter limits one key and nonce pair to about 256 GB, which it notes may be too small for disk encryption. Disk and volume encryption usually use length-preserving modes instead; see the Database and Storage Encryption Guide.
In depth: AES-GCM
Threat model: network attackers observing and modifying traffic (MITRE ATT&CK T1557 Adversary-in-the-Middle), attackers forcing weaker settings (T1600 Weaken Encryption), and local attackers measuring timing on shared hardware.
Architecture in words: the AES key encrypts a zero block to derive the GHASH key H. Data is encrypted with AES in counter mode starting from a block derived from the nonce. GHASH multiplies the associated data, ciphertext and lengths by H in GF(2^128), and the result is masked with an encrypted counter block to give the tag. Everything rests on one AES key and on counters never repeating.
Failure modes: nonce reuse after a crash or a restored VM snapshot exposing H; random nonces at very high volume; software AES with lookup tables on shared hosts; truncated tags (SP 800-38D permits shorter tags, which weaken forgery resistance); and keys used past the record limits in custom protocols.
Controls: hardware AES or constant-time library code; protocol-derived nonces; 128-bit tags only; count-based rekeying; AES-GCM-SIV where nonce state cannot be trusted.
In depth: ChaCha20-Poly1305
Threat model: the same network attacker, plus attackers on low-power devices where side-channel exposure of software AES would otherwise be a concern.
Architecture in words: ChaCha20 block 0 generates a one-time Poly1305 key from the main key and nonce; encryption runs from block 1 using a 32-bit counter. Poly1305 authenticates the associated data, ciphertext, padding and both lengths into a 128-bit tag. No lookup tables, so timing does not depend on secret data.
Failure modes: nonce reuse (keystream and Poly1305 key repeat); tag truncation, which RFC 8439 forbids; non-constant-time tag comparison with memcmp or similar, which RFC 8439 also prohibits; exceeding the 256 GB per-nonce counter in file encryption; and assuming FIPS coverage that the module does not have.
Controls: library AEAD APIs that manage nonces and comparison; full tags; counting integrity failures in DTLS or QUIC style protocols; XChaCha20 through a mature library for random-nonce designs; confirming validation scope before deployment in regulated environments.
TLS 1.3, QUIC and VPN choices
RFC 8446 defines five TLS 1.3 cipher suites: TLS_AES_128_GCM_SHA256 (0x13,0x01), TLS_AES_256_GCM_SHA384 (0x13,0x02), TLS_CHACHA20_POLY1305_SHA256 (0x13,0x03), TLS_AES_128_CCM_SHA256 (0x13,0x04) and TLS_AES_128_CCM_8_SHA256 (0x13,0x05). Section 9.1 says a TLS-compliant application MUST implement TLS_AES_128_GCM_SHA256 and SHOULD implement the AES-256-GCM and ChaCha20-Poly1305 suites, unless an application profile says otherwise. TLS 1.3 suites name only the AEAD and hash, so the choice is independent of certificate and key exchange.
- Public web and API endpoints: enable the three GCM and ChaCha20 suites. Many TLS libraries let a server prefer AES-GCM but honour a client that lists ChaCha20-Poly1305 first, which serves both hardware classes well. Check your library's documentation for the exact option.
- QUIC and HTTP/3: RFC 9001 allows any TLS 1.3 suite except TLS_AES_128_CCM_8_SHA256, which has no header protection scheme. AES suites use AES-based header protection and ChaCha20-Poly1305 uses ChaCha20-based header protection. See the HTTP/2, HTTP/3 and QUIC Security Guide.
- TLS 1.2 legacy: RFC 9325 recommends four ECDHE AES-GCM suites for TLS 1.2 and does not specify TLS 1.3 suites. See the TLS Server Configuration Baseline Guide for the full baseline.
- WireGuard: no cipher agility. The handshake is Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s and transport data uses ChaCha20-Poly1305 with a counter nonce. If policy requires AES-GCM or a validated module, that is a protocol choice (for example IPsec), not a setting. See How VPNs Work.
IoT and constrained devices
Constrained devices change the question, because the choice is often fixed by the radio or protocol stack rather than by the developer.
- DTLS and TLS IoT profiles: RFC 7925 (Standards Track, July 2016) makes TLS_PSK_WITH_AES_128_CCM_8 mandatory for its pre-shared key profile and TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 for its raw public key and certificate profiles. CCM_8 carries an 8-octet tag, and the RFC warns that shorter tags raise the chance of a successful forgery depending on how many verifications are allowed per key, and that the PSK suite has no forward secrecy.
- Microcontrollers with an AES peripheral: many have a hardware AES block, so AES-CCM or AES-GCM are cheaper than ChaCha20 in practice. Check whether the peripheral is constant time and whether GHASH is accelerated.
- Microcontrollers without AES hardware: ChaCha20-Poly1305 gives constant-time software at good speed, where the protocol allows it.
- Lightweight alternative: NIST SP 800-232 (Final, 13 August 2025) standardises Ascon-based authenticated encryption, hashing and extendable output for resource-constrained devices such as IoT sensors. Consider it for new designs where both ends are under your control and libraries are mature.
- Device keys are machine identities: per-device symmetric keys and PSKs are non-human credentials. Inventory them, give each device its own key, and plan rotation. See the IoT Device Certificates vs Pre-Shared Keys and the Identity for IoT Fleets Guide.
Decision guidance and trade-offs
| Situation | Choose | Reason |
|---|---|---|
| Cloud services, load balancers, service mesh on modern CPUs | AES-GCM (also enable ChaCha20 for external clients) | Hardware speed; mandatory TLS 1.3 suite |
| FIPS 140-3 or US federal scope | AES-GCM in a validated module | NIST-specified mode; confirm module boundary |
| Mobile app talking to your API | Offer both; let the client lead | Low-end devices benefit from ChaCha20 |
| Long-lived tunnels or bulk links with high volume per key | Either, with count-based rekeying; ChaCha20 has more headroom | GCM record limits are reached sooner |
| Application field encryption with many stateless writers | AES-GCM-SIV or XChaCha20-Poly1305 via a library, or per-writer keys | 96-bit random nonces collide at scale |
| Constrained IoT on DTLS | Whatever the profile mandates (often AES-CCM); 16-octet tags where allowed | Interoperability and hardware AES blocks |
- Small organisations: do not choose at all beyond library defaults. Keep TLS 1.3 enabled with default suites, keep libraries patched, and use a managed KMS for data encryption.
- Large organisations: set a cryptographic standard naming both AEADs, the contexts each is approved for, key sizes, nonce strategy and rekey limits, and enforce it through scanning and a Cryptographic Inventory and CBOM Guide style inventory.
Worked scenarios
Scenario 1, a consumer API with a global Android user base. The team enables TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256 on the edge, with server preference for AES-GCM but client preference honoured for ChaCha20. Handshake logs then show which client classes negotiate ChaCha20, confirming the setting earns its place.
Scenario 2, a token encryption service restored from snapshot. A service encrypts session tokens with AES-GCM using an in-memory counter. After a VM restore the counter restarts and nonces repeat under the same key. The fix is to derive a fresh data key at every process start from the KMS, bind key version in associated data, and alert on duplicate nonce and key pairs in a test harness. Moving to ChaCha20 would not have helped: the flaw is nonce management, not the cipher.
Scenario 3, a federal workload with a WireGuard proposal. Engineers propose WireGuard for site links. Because the environment requires FIPS 140-3 validated modules and WireGuard has no cipher choice, the architecture review selects IPsec with AES-GCM in a validated module instead, and records the decision in the cryptographic standard.
How to implement
- Inventory: list every TLS endpoint, VPN, SSH server and application call site that encrypts data, with the negotiated or configured AEAD and key lifetime.
- Set the standard: approve AES-GCM and ChaCha20-Poly1305 for transport, define where each is required or preferred, mandate 128-bit tags, and state rekey limits per protocol.
- Configure transport: enable TLS 1.3 suites per the decision table; for TLS 1.2 keep only AEAD suites per RFC 9325.
- Fix application crypto: replace direct cipher calls with a high-level AEAD API that generates nonces; persist counters or use per-process keys; add AES-GCM-SIV or XChaCha20 where writers are stateless.
- Test: RFC 8439 and NIST test vectors, negative tests (tampered tag, ciphertext and associated data must fail), and a handshake scan of each endpoint to confirm the negotiated suite per client type.
- Pilot and roll out: change suite order on a canary pool, compare handshake failures and latency by client, then widen.
- Roll back: keep the previous suite list in configuration management; application formats must carry a version or key ID so you can read old ciphertext after a change. See the Crypto-Agility Guide.
Detection and measurement
Log the negotiated TLS version and cipher suite at load balancers and proxies, AEAD decryption failures by key ID and peer, KeyUpdate events, and encryption counts per key for application keys. A rise in tag failures is either corruption or probing; in DTLS and QUIC it is also a limit to enforce.
- AEAD coverage: percentage of TLS connections using an AEAD suite (target 100%).
- Suite mix by client class: share of handshakes on ChaCha20-Poly1305 versus AES-GCM, to confirm low-end clients get the faster option.
- Keys near limits: number of application or tunnel keys above 50% of their documented usage limit.
- Nonce hygiene: application call sites using caller-supplied IVs (target zero).
- Integrity failures: AEAD tag failures per million records, trended and alerted.
Common failure patterns
- Choosing by headline speed: switching servers to ChaCha20-only on hardware with AES instructions loses performance and drops the mandatory TLS 1.3 suite.
- Treating ChaCha20 as a fix for nonce bugs: it fails the same way on reuse. Fix the nonce source.
- Custom protocols without rekeying: AES-GCM channels that run for months on one key exceed record limits silently.
- Short tags by default: CCM_8 or truncated GCM tags chosen to save bytes where 16-octet tags were possible.
- Assuming validation coverage: deploying ChaCha20-Poly1305 or WireGuard into a FIPS 140-3 scope without checking the module certificate. See the FIPS 140-3 and Cryptographic Module Validation Guide.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | SC-13 Cryptographic Protection | Approved algorithm and mode selection |
| NIST SP 800-53 Rev 5 | SC-8 and SC-8(1) Transmission Confidentiality and Integrity | AEAD in TLS, QUIC and VPNs |
| NIST SP 800-53 Rev 5 | SC-12 Cryptographic Key Establishment and Management | Rekeying before usage limits |
| NIST SP 800-53 Rev 5 | SC-28 Protection of Information at Rest | Application and field encryption |
| NIST CSF 2.0 | PR.DS-01, PR.DS-02 | Data at rest and in transit protected |
| CIS Controls v8.1 | 3.10 Encrypt Sensitive Data in Transit; 3.11 Encrypt Sensitive Data at Rest | Where AEAD choices apply |
| ISO/IEC 27001:2022 | Annex A 8.24 Use of cryptography | Cryptographic standard and key management rules |
| MITRE ATT&CK | T1557 Adversary-in-the-Middle; T1600 Weaken Encryption | Interception and forced downgrade the choice must resist |
Practitioner checklist
- Enable TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256 on public TLS 1.3 endpoints unless a profile says otherwise.
- Confirm AES hardware on servers and identify client classes that lack it.
- Use only 128-bit tags; avoid CCM_8 unless a profile mandates it.
- Never let application code supply its own IVs; use library AEAD APIs.
- Rotate AES-GCM keys by count in custom protocols, using RFC 8446 and RFC 9001 limits as reference points.
- Count AEAD integrity failures in DTLS and QUIC style protocols and close at the limit.
- Check FIPS 140-3 module coverage before approving ChaCha20-Poly1305 or WireGuard in regulated scopes.
- Give each IoT device its own key and record it in the machine identity inventory.
Standards and references
- IETF: RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3
- IRTF: RFC 8439 ChaCha20 and Poly1305 for IETF Protocols
- NIST: SP 800-38D Galois/Counter Mode (GCM) and GMAC
- IETF: RFC 9001 Using TLS to Secure QUIC
- IETF: RFC 9325 Recommendations for Secure Use of TLS and DTLS
- IETF: RFC 7925 TLS/DTLS Profiles for the Internet of Things
- IRTF: Usage Limits on AEAD Algorithms (Internet-Draft)
- NIST: SP 800-232 Ascon-Based Lightweight Cryptography Standards
Related NHI Mgmt Group resources: Authenticated Encryption and Block Cipher Modes Guide · TLS Server Configuration Baseline Guide · Cryptographic Key Management Guide · Crypto-Agility Guide