Skip to content
CyberXplained

ChaCha20 Encryption

CoreSymmetric

ChaCha20 Encryption Simulator

Experiment with ChaCha20 encryption and see how it transforms your data

ChaCha20 Encryption Simulator

What is ChaCha20?

ChaCha20 is a modern stream cipher designed by Daniel J. Bernstein in 2008 as a successor to his earlier Salsa20 cipher. It's designed to provide high security while being efficient in software implementations, particularly on CPUs without specialized cryptographic instructions.

The name "ChaCha" comes from the cipher's core operation, which performs a series of addition, rotation, and XOR operations (ARX) that resembles a choreographed dance. The "20" refers to the number of rounds (iterations) the algorithm performs.

Key Features

  • 256-bit key (32 bytes)
  • 96-bit nonce (12 bytes)
  • 64-bit counter
  • 20 rounds of ARX operations
  • Produces 64-byte (512-bit) keystream blocks
  • No table lookups (resistant to cache-timing attacks)
  • Highly parallelizable

Advantages

  • High performance on modern CPUs
  • Strong security with no known practical attacks
  • Resistant to side-channel attacks
  • Simple design with thorough analysis
  • No need for specialized hardware
  • Constant-time operation
  • Widely adopted in modern protocols

History and Development

Origins

ChaCha20 was designed by Daniel J. Bernstein, a mathematician, cryptographer, and computer scientist. It was created as an improvement to his earlier Salsa20 cipher, which was submitted to the eSTREAM project in 2005 and was selected as part of the eSTREAM portfolio in 2008.

Design Goals

Bernstein designed ChaCha20 with several specific goals in mind: high security margins, high performance in software without specialized instructions, resistance to timing attacks, and simplicity of implementation. The design was influenced by the ARX (Addition, Rotation, XOR) paradigm, which was gaining popularity for its efficiency and security.

Timeline of Development

2005

Salsa20 submitted to the eSTREAM project, a competition to identify new stream ciphers

2008

Salsa20/12 (12-round variant) selected for the eSTREAM portfolio; ChaCha20 introduced as an improved version with better diffusion properties

2013

Google selects ChaCha20-Poly1305 for use in TLS connections from Android devices, citing performance benefits over AES-GCM on devices without hardware acceleration

2015

IETF standardizes ChaCha20-Poly1305 in RFC 7539 for use in Internet protocols

2018

RFC 8439 obsoletes RFC 7539, providing updated guidance on ChaCha20-Poly1305

2018+

Widespread adoption in TLS 1.3, WireGuard VPN, Signal Protocol, and other security-critical applications

From Salsa20 to ChaCha20

ChaCha20 was designed to address some of the perceived weaknesses in Salsa20 while maintaining its strengths. The key differences include:

  • Improved diffusion: ChaCha20 achieves full diffusion (where each input bit affects all output bits) faster than Salsa20
  • Modified rotation constants: ChaCha20 uses different rotation values in its quarter-round function
  • Input arrangement: The state matrix is arranged differently to improve mixing
  • Same security level: Both ciphers offer similar security guarantees with 20 rounds

Applications and Variants

Common Applications

  • TLS 1.3: Used as a cipher suite in the latest TLS protocol
  • IETF ChaCha20-Poly1305: Authenticated encryption with associated data (AEAD)
  • WireGuard VPN: Used for encryption in this modern VPN protocol
  • Signal Protocol: Used in the secure messaging application
  • SSH: Supported in OpenSSH
  • Tor Network: Used for encryption in the Tor anonymity network
  • Mobile Applications: Preferred on mobile devices without AES hardware acceleration
  • Libsodium: Popular cryptography library that implements ChaCha20

Standardization

  • RFC 7539: ChaCha20 and Poly1305 for IETF Protocols
  • RFC 8439: ChaCha20 and Poly1305 for IETF Protocols (obsoletes RFC 7539)
  • NIST SP 800-175B: Recognized as an approved algorithm
  • TLS 1.3 (RFC 8446): Included as a recommended cipher suite

Variants and Related Algorithms

Comparison with AES

FeatureChaCha20AES
TypeStream cipherBlock cipher
Key Size256 bits128/192/256 bits
Software PerformanceExcellentGood (better with AES-NI)
Hardware AccelerationRarely neededWidely available (AES-NI)
Side-Channel ResistanceStrongVulnerable without care
Memory RequirementsLowHigher (S-boxes)
StandardizationIETF, TLS 1.3NIST, worldwide

How ChaCha20 Works

ChaCha20 is a stream cipher that generates a keystream which is then XORed with the plaintext to produce ciphertext. The core of ChaCha20 is its state transformation function, which creates a pseudorandom keystream from a key, nonce, and counter.

State Initialization

ChaCha20 begins with a 4×4 matrix of 32-bit words (16 words total, 512 bits):

ChaCha20 State Matrix

constant
constant
constant
constant
key
key
key
key
key
key
key
key
counter
counter
nonce
nonce

The ChaCha20 state is a 4×4 matrix of 32-bit words. The first row contains constants ("expand 32-byte k"), the next two rows contain the 256-bit key, and the final row contains a 64-bit counter and a 96-bit nonce.

Constants

The first row contains the constants "expand 32-byte k" in ASCII:

0x61707865, 0x3320646e, 0x79622d32, 0x6b206574

Key

The next two rows contain the 256-bit key as eight 32-bit words:

key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]

Counter

The first part of the last row contains a 64-bit counter as two 32-bit words:

counter[0], counter[1]

Nonce

The remainder of the last row contains a 96-bit nonce as three 32-bit words:

nonce[0], nonce[1], nonce[2]

Core Operations

ChaCha20 is based on the ARX (Addition, Rotation, XOR) paradigm, which combines three simple operations:

Addition

32-bit unsigned integer addition modulo 2³². This operation provides non-linearity and is efficient on modern CPUs.

Rotation

Bitwise rotation (circular shift) of 32-bit words. This diffuses changes throughout the bits of a word.

XOR

Bitwise exclusive OR operation. This combines bits in a non-linear way and is reversible.

Quarter Round Operation

abcda+bbcd⊕arotate 16a+bb⊕cc+dd⊕arotate 12a+bb⊕cc+dd⊕arotate 8a+bb⊕cc+dd⊕arotate 7+⊕⊕+

The quarter round is the core operation in ChaCha20. It applies a series of addition, XOR, and rotation operations to four 32-bit words. This operation is applied to columns and diagonals of the 4x4 state matrix in alternating rounds, creating a highly diffused output.

Round Structure

ChaCha20 applies 20 rounds to the state matrix, alternating between column rounds and diagonal rounds:

ChaCha20 Round Operations

Column Round

In column rounds, quarter rounds are applied to each column of the state matrix.

Diagonal Round

In diagonal rounds, quarter rounds are applied to each diagonal of the state matrix.

ChaCha20 alternates between column rounds and diagonal rounds, with 10 iterations of each for a total of 20 rounds. This pattern ensures that every element in the state matrix is thoroughly mixed with every other element.

After all 20 rounds are complete, the final state is added word-by-word to the initial state. This addition step ensures that the transformation is invertible and increases security.

Keystream Generation and Encryption

Once the state transformation is complete, the resulting 512-bit block is used as a keystream:

  1. The 16 words of the final state are serialized to form a 64-byte keystream block
  2. This keystream is XORed with the plaintext to produce ciphertext
  3. For messages longer than 64 bytes, the counter is incremented and the process repeats
  4. Decryption works exactly the same way, as XOR is its own inverse

Encryption Formula

Ciphertext = Plaintext ⊕ ChaCha20(key, counter, nonce)

Decryption Formula

Plaintext = Ciphertext ⊕ ChaCha20(key, counter, nonce)

ChaCha20 Pseudocode

// ChaCha20 Quarter Round function
function quarterRound(a, b, c, d) {
    a += b; d ^= a; d <<<= 16;
    c += d; b ^= c; b <<<= 12;
    a += b; d ^= a; d <<<= 8;
    c += d; b ^= c; b <<<= 7;
    return [a, b, c, d];
}

// Initialize ChaCha20 state
function initState(key, counter, nonce) {
    // Constants: "expand 32-byte k" in ASCII
    const state = [
        0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,  // Constants
        // 256-bit key (8 x 32-bit words)
        key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7],
        // 64-bit counter (2 x 32-bit words)
        counter[0], counter[1],
        // 96-bit nonce (3 x 32-bit words)
        nonce[0], nonce[1], nonce[2]
    ];
    return state;
}

// ChaCha20 block function
function chacha20Block(state) {
    // Create working copy of state
    let x = state.slice();
    
    // 20 rounds (10 column rounds, 10 diagonal rounds)
    for (let i = 0; i < 10; i++) {
        // Column round
        [x[0], x[4], x[8], x[12]] = quarterRound(x[0], x[4], x[8], x[12]);
        [x[1], x[5], x[9], x[13]] = quarterRound(x[1], x[5], x[9], x[13]);
        [x[2], x[6], x[10], x[14]] = quarterRound(x[2], x[6], x[10], x[14]);
        [x[3], x[7], x[11], x[15]] = quarterRound(x[3], x[7], x[11], x[15]);
        
        // Diagonal round
        [x[0], x[5], x[10], x[15]] = quarterRound(x[0], x[5], x[10], x[15]);
        [x[1], x[6], x[11], x[12]] = quarterRound(x[1], x[6], x[11], x[12]);
        [x[2], x[7], x[8], x[13]] = quarterRound(x[2], x[7], x[8], x[13]);
        [x[3], x[4], x[9], x[14]] = quarterRound(x[3], x[4], x[9], x[14]);
    }
    
    // Add original state to the result
    for (let i = 0; i < 16; i++) {
        x[i] += state[i];
    }
    
    return x;
}

// ChaCha20 encryption/decryption
function chacha20Encrypt(plaintext, key, counter, nonce) {
    const state = initState(key, counter, nonce);
    let ciphertext = new Uint8Array(plaintext.length);
    
    // Process plaintext in 64-byte blocks
    for (let i = 0; i < plaintext.length; i += 64) {
        const keyStream = chacha20Block(state);
        
        // Increment counter for next block
        state[12]++;
        if (state[12] === 0) state[13]++;
        
        // XOR keystream with plaintext to produce ciphertext
        for (let j = 0; j < 64 && i + j < plaintext.length; j++) {
            const keyByte = (keyStream[Math.floor(j / 4)] >>> ((j % 4) * 8)) & 0xff;
            ciphertext[i + j] = plaintext[i + j] ^ keyByte;
        }
    }
    
    return ciphertext;
}

// Note: Decryption is identical to encryption since XOR is its own inverse
function chacha20Decrypt(ciphertext, key, counter, nonce) {
    return chacha20Encrypt(ciphertext, key, counter, nonce);
}

This pseudocode demonstrates the core operations of ChaCha20. The actual implementation would include additional details like proper handling of byte ordering and efficient bit operations.

Real-World Implementations

ChaCha20 has been implemented in numerous cryptographic libraries and protocols. Here are some notable implementations:

Software Libraries

  • libsodium: A modern, easy-to-use cryptographic library with ChaCha20 and XChaCha20 implementations
  • OpenSSL: Added ChaCha20-Poly1305 support in version 1.1.0
  • BoringSSL: Google's fork of OpenSSL with optimized ChaCha20 implementation
  • Crypto++: C++ library with ChaCha20 support
  • NaCl: Networking and Cryptography library by Daniel J. Bernstein
  • Bouncy Castle: Java and C# implementations

Protocol Implementations

  • TLS 1.3: Includes ChaCha20-Poly1305 as a recommended cipher suite
  • WireGuard: Modern VPN protocol using ChaCha20 for encryption
  • Signal Protocol: End-to-end encryption for messaging
  • OpenSSH: Supports ChaCha20-Poly1305 for secure connections
  • Tor: Uses ChaCha20-Poly1305 in its encryption layers
  • Noise Protocol Framework: Cryptographic framework used in many applications

Optimized Implementations

ChaCha20 has been optimized for various platforms to achieve maximum performance:

SIMD Vectorization

Implementations using SSE2, AVX2, NEON, and other SIMD instruction sets can process multiple words in parallel, significantly increasing throughput.

Multi-threading

ChaCha20's counter mode allows for easy parallelization, with different counter values processed by different threads.

Hardware Acceleration

Some newer ARM processors include dedicated instructions for ChaCha20, and some FPGAs and ASICs have been designed with ChaCha20 acceleration.

Performance Benchmarks

ChaCha20 is known for its excellent software performance, especially on platforms without AES hardware acceleration:

PlatformChaCha20AES-256-GCMAdvantage
ARM Cortex-A7 (no AES-NI)~150 MB/s~25 MB/s6x faster
Intel Core i5 (no AES-NI)~400 MB/s~100 MB/s4x faster
Intel Core i7 (with AES-NI)~700 MB/s~900 MB/s0.8x slower
ARM Cortex-A72 (with AES)~800 MB/s~1000 MB/s0.8x slower

Note: These are approximate values and actual performance can vary based on specific implementations, compiler optimizations, and hardware details.

Security Analysis

ChaCha20 was designed with security as a primary goal, building on the lessons learned from previous stream ciphers. Its security has been extensively analyzed by cryptographers since its introduction.

Security Strengths

  • 256-bit key provides strong security against brute force attacks
  • ARX design is resistant to many cryptanalytic techniques
  • No known practical attacks against the full 20-round version
  • Constant-time implementation resistant to timing attacks
  • No table lookups, eliminating cache-timing vulnerabilities
  • Simple design allows for thorough security analysis
  • Nonce-misuse resistance with XChaCha20 variant
  • Highly diffusive design ensures changes propagate quickly
  • No known biases in the keystream

Security Considerations

  • Nonce reuse is catastrophic (as with any stream cipher)
  • Reduced-round variants (ChaCha8, ChaCha12) have smaller security margins
  • Best attacks can break up to 7 rounds (far from the full 20)
  • Requires proper integration with authentication (e.g., Poly1305)
  • Implementation errors can still lead to vulnerabilities
  • Relatively new compared to algorithms like AES
  • 96-bit nonce may be insufficient for some applications (use XChaCha20)
  • Counter overflow can lead to keystream reuse (unlikely in practice)

Cryptanalysis Results

Several cryptanalysis efforts have been directed at ChaCha20 and its variants:

YearResearchersAttack TypeRoundsComplexity
2008Aumasson et al.Differential7/202^248
2013Shi et al.Differential6/202^205
2015Choudhuri & MaitraDifferential7/202^237.7
2020Dey et al.Differential-Linear7.5/202^230.86
2022Beierle et al.Differential7/202^233

All known attacks on ChaCha20 are theoretical and only apply to reduced-round versions. The full 20-round ChaCha20 maintains a significant security margin against these attacks.

Security Proofs and Guarantees

While ChaCha20 does not have formal security proofs like some other cryptographic primitives, it has several properties that contribute to its security:

  • Indistinguishability from Random: The ChaCha20 keystream is computationally indistinguishable from a truly random stream, assuming the security of the core function.
  • Avalanche Effect: Small changes in the input (key, nonce, or counter) result in completely different outputs, with changes propagating throughout the state.
  • Statistical Properties: The keystream passes standard statistical tests for randomness, showing no detectable patterns or biases.
  • Side-Channel Resistance: The algorithm's design inherently resists timing attacks and other side-channel vulnerabilities when properly implemented.

When combined with Poly1305 in the ChaCha20-Poly1305 AEAD construction, it provides provable security properties including confidentiality and authenticity under standard cryptographic assumptions.

Best Practices

  • Always use ChaCha20 with an authentication mechanism (e.g., Poly1305)
  • Never reuse a nonce with the same key
  • Consider XChaCha20 for applications where nonces are randomly generated
  • Use the full 20-round version for security-critical applications
  • Prefer vetted implementations from cryptographic libraries
  • Keep keys secure and generate them using a cryptographically secure random number generator
  • Use ChaCha20-Poly1305 in AEAD mode when possible
  • Implement secure key management practices
  • Update implementations to address any discovered vulnerabilities

Security Advisory

Like all stream ciphers, ChaCha20 is vulnerable to key-stream reuse attacks. If the same key and nonce are used to encrypt two different messages, an attacker can XOR the ciphertexts together to obtain the XOR of the plaintexts, which can lead to information leakage or even full message recovery.

Always ensure that each (key, nonce) pair is used only once. For systems where this is difficult to guarantee, consider using XChaCha20 with its extended 192-bit nonce.