ChaCha20 Encryption
Modern stream cipher with optional authentication
Client-Side Security
ChaCha20-Poly1305 (RFC 8439) is the recommended authenticated encryption mode. Plain ChaCha20 provides no integrity — always use with Poly1305 for production encryption. For 96-bit IETF nonces: enforce strict nonce uniqueness (counter-based or per-session random). XChaCha20-Poly1305 (192-bit nonce) enables safe random nonce generation.
Initial block counter value (usually 0 for encryption, same value for decryption)
About ChaCha20
ChaCha20 is an ARX stream cipher designed by Daniel J. Bernstein in 2008 as an improved variant of Salsa20. It operates on the same 4×4 matrix of 32-bit words (512-bit state) but with a redesigned quarter-round function and a different state initialization layout. ChaCha20’s quarter-round achieves better per-round bit diffusion than Salsa20: any single bit change propagates to all 16 state words within 2 rounds instead of Salsa20’s 4 rounds. The IETF variant (RFC 8439) uses a 96-bit nonce (3×32 bits) and a 32-bit counter (supporting up to 2³² × 64 = 256 GB per nonce), while Bernstein’s original uses a 64-bit nonce and 64-bit counter.
ChaCha20-Poly1305 (RFC 7539, 2015; updated RFC 8439, 2018) is the IETF-standardized AEAD construction combining ChaCha20 (for encryption) with Poly1305 (for authentication). A one-time Poly1305 key is derived from the first 32 bytes of ChaCha20 output with counter=0. The construction provides 128-bit authentication tags. Google deployed ChaCha20-Poly1305 in TLS for Android and low-power devices in 2014 (Langley and Borsini). It is mandatory in TLS 1.3 (RFC 8446) as TLS_CHACHA20_POLY1305_SHA256, selected for AES-less hardware (mobile, embedded) and as AES-NI-independent alternative.
Algorithm Comparison
| Algorithm | Type | Key Length | Nonce Length | Best Use Case |
|---|---|---|---|---|
| ChaCha20 | Stream Cipher | 256 bits | 96 bits (12 bytes) | Protocol implementation research and testing; cryptographic streaming where authentication is provided at a higher protocol layer; performance benchmarking without AEAD overhead |
| ChaCha20-Poly1305 | AEAD | 256 bits | 96 bits (12 bytes) | TLS 1.3, WireGuard, SSH, QUIC, Signal Protocol authenticated message encryption; mobile and embedded devices without AES-NI; internet-facing services requiring timing-attack-resistant AEAD |
| XChaCha20 | Stream Cipher | 256 bits | 192 bits (24 bytes) | File and database field encryption where nonce uniqueness via counter cannot be guaranteed; libsodium secretstream for chunked file encryption; backup encryption with independently generated nonces |
| XChaCha20-Poly1305 | AEAD | 256 bits | 192 bits (24 bytes) | At-rest data encryption requiring both random nonce generation and 128-bit authentication; libsodium-based application storage encryption; recommended default AEAD when nonce management cannot be centrally coordinated |
How ChaCha20 Works
ChaCha20 initializes a 4×4 matrix with the same 4 constant words as Salsa20 (“expa nd 32-byte k”), but in a different layout: row 0 = constants, row 1-2 = 256-bit key (8×32 bits), row 3 = [counter₀ | nonce₀ | nonce₁ | nonce₂] for IETF (32-bit counter + 96-bit nonce). The quarter-round on (a,b,c,d) executes four add-xor-rotate steps with rotations of 16, 12, 8, and 7 bits: a+=b; d^=a; d‹‹‹16; c+=d; b^=c; b‹‹‹12; a+=b; d^=a; d‹‹‹8; c+=d; b^=c; b‹‹‹7.
ChaCha20’s double round applies quarter-rounds to four columns of the matrix (column round), then to four diagonals (diagonal round). Compared to Salsa20’s row-then-diagonal structure, ChaCha20’s column-then-diagonal pattern with the new rotation constants (16-12-8-7 vs Salsa20’s 7-9-13-18) achieves full bit diffusion across all 16 words in 2 rounds instead of 4. After 20 rounds (10 double rounds), the output block = the 20-round transformed state XOR the original state. The 64-byte output block XORs with plaintext for encryption.
AEAD: Authenticated Encryption
ChaCha20-Poly1305 AEAD (RFC 8439): to authenticate-and-encrypt a message, derive a one-time Poly1305 key by running ChaCha20 with the same (key, nonce) and counter=0, taking the first 32 bytes of output. Then encrypt the plaintext with ChaCha20 starting at counter=1. Compute the Poly1305 MAC over: [padded AAD] || [padded ciphertext] || [little-endian uint64 len(AAD)] || [little-endian uint64 len(ciphertext)]. Append the 16-byte Poly1305 tag to the ciphertext.
XChaCha20-Poly1305: derives a 256-bit subkey via HChaCha20 (ChaCha20’s counterpart to HSalsa20) from the first 128 bits of a 192-bit nonce and the original 256-bit key. The subkey and the remaining 64-bit nonce feed into ChaCha20-Poly1305. The 192-bit nonce enables random nonce generation without birthday concern: with 2^32 messages the collision probability remains 2^(-128). libsodium implements this as crypto_aead_xchacha20poly1305_ietf_encrypt.
Key Features
- Superior per-round diffusion vs Salsa20: ChaCha20’s quarter-round rotation constants (16-12-8-7) achieve full diffusion of any bit flip to all 16 state words within 2 rounds; Salsa20 requires 4 rounds for equivalent diffusion. This means ChaCha20/8 (8 rounds) gives equivalent security to Salsa20/16, enabling safe use in more aggressive round-count reductions.
- IETF standardization (RFC 8439, 2018): ChaCha20-Poly1305 is the IETF-standardized AEAD; TLS 1.3 (RFC 8446) mandates TLS_CHACHA20_POLY1305_SHA256; adopted in WireGuard, SSH OpenSSH chacha20-poly1305@openssh.com, QUIC, Signal Protocol, Noise Protocol Framework, and Android TLS stack.
- AES-independent performance: designed before AES-NI hardware acceleration; excels on ARM Cortex-A53/A55, embedded microcontrollers, RISC-V, and MIPS architectures; 25%–40% faster than AES-GCM on hardware without AES-NI instructions; preferred for IoT, mobile, and resource-constrained deployment.
- 96-bit IETF nonce (3×32 bits): enables session-unique nonce with 32-bit counter per session (up to 256 GB per nonce) alongside 64-bit stream counter when retaining the Bernstein format; XChaCha20 extends to 192-bit nonce for applications requiring random nonce generation without birthday risk.
- No known attacks on ChaCha20/20 (full 20 rounds) as of 2025. Best published reduced-round analysis: Shi et al. (2012) on ChaCha20/6 with probabilistic neutral bit differential. Full security analysis confirms ChaCha20/20 security level is at least 256 bits for single-target attacks.
Security Considerations
- Nonce reuse breaks ChaCha20-Poly1305 AEAD: two messages encrypted with the same (key, nonce) expose both plaintexts via XOR, and the Poly1305 authentication key (derived from counter=0 output) is revealed, completely destroying authentication. Enforce per-message nonce uniqueness. For TLS 1.3: nonce is XOR-derived from a sequence number, ensuring uniqueness within a session.
- IETF nonce (96-bit) counter limit: the 32-bit counter supports at most 2^32 × 64 bytes = 256 GB per (key, nonce). For data volumes exceeding 256 GB under a single nonce, either increment the nonce or rekey. In practice, TLS 1.3 renegotiates keys via key_update before approaching this limit.
- Poly1305 one-time key requirement: the Poly1305 key must be used for exactly one message per nonce. If ChaCha20-Poly1305 nonce is reused, the Poly1305 key is reused, breaking authentication (Bernstein 2005 forgery attack on repeated Poly1305 keys). RFC 8439 Section 2.8 specifies the one-key-per-nonce construction to prevent this.
- Authentication tag truncation: RFC 8439 mandates the full 128-bit (16-byte) Poly1305 tag. Truncating the authentication tag (e.g., to 64 bits for space savings) reduces the forgery resistance from 2^{-128} to 2^{-64} and is not compliant with TLS 1.3 requirements. Always use the 16-byte full-length tag.
Real-World Usage
- TLS 1.3 (RFC 8446): TLS_CHACHA20_POLY1305_SHA256 is a mandatory cipher suite in TLS 1.3; implemented in OpenSSL, BoringSSL, NSS, WolfSSL, and mbedTLS; preferred for clients lacking AES-NI (mobile, embedded) and provides timing-attack resistance via constant-time ARX operations.
- WireGuard VPN: ChaCha20-Poly1305 is the sole symmetric cipher in WireGuard’s cryptographic module (Donenfeld 2017, Linux kernel 5.6); combined with Curve25519 (key exchange), Poly1305 (MAC), BLAKE2 (hashing), and SipHash (hashtable); chosen for simplicity, auditability, and performance on constrained hardware.
- Signal Protocol / Double Ratchet Algorithm: Signal uses ChaCha20-Poly1305 as the symmetric AEAD in the Double Ratchet message encryption after the X3DH key agreement; also adopted by WhatsApp, Facebook Messenger’s secret conversations, Matrix protocol, and Keybase.
- OpenSSH chacha20-poly1305@openssh.com: OpenSSH 6.5 (2014) became the first major SSH implementation to adopt ChaCha20-Poly1305; the cipher uses two independent ChaCha20 instances (one for packet length, one for payload) to eliminate timing leakage from variable-length padding.
- Google mobile TLS deployment (2014): Adam Langley and Thai Duong deployed ChaCha20-Poly1305 in Chrome and Android TLS for connections to Google services; performance measurements showed 3× faster than AES-128-GCM on Nexus 5 ARM Cortex-A15 without AES-NI, influencing subsequent IETF standardization.
References
Related Tools
AES Encryption/Decryption
Securely encrypt and decrypt text using AES algorithm
RC Cipher Family (RC4/RC5/RC6)
RC family stream and block ciphers including RC4, RC4-Drop, RC5, and RC6 (AES finalist) with multiple modes
Blowfish Encryption/Decryption
Fast symmetric block cipher with variable key length (32-448 bits), designed by Bruce Schneier