Skip to content

ChaCha

This algorithm is recommended

Use ChaCha in it's XChaCha20-Poly1305 or ChaCha20-Poly1305 variations.

XChaCha20-Poly1305 and ChaCha20-Poly1305 are considered secure6 and fast. It has a strong security level and provides authentication (AEAD).

It is arguably easier to use than AES, because it has less (insecure) variations and modes of operation. However, when using AES as AES-256-GCM, the differences in security to ChaCha20-Poly1305 are negligible. Note that AES is only fast to use when hardware acceleration is available - while this is very common nowadays, it might be a constraint to consider. ChaCha can be implemented very fast in software only and does not require special CPU instructions.

Disclaimer: How to use recommendations from Cryptography Primer

The recommendations on Cryptography Primer are based on research on multiple sources that are freely available online, such as:

  • Research papers available on e.g. arxiv.org1
  • Recommendations of Cryptographic Library authors
  • BSI technical guidelines4
  • NIST publications5
  • Blogs of reknown cryptographers or cybersecurity experts
  • crypto.stackexchange.com2
  • security.stackexchange.com3
  • and occasionally other sources

As should always be the case, you should not take recommendations from a single source for granted, but instead find at least a second - or better, third - source that confirms this recommendation.

Also, if you are using recommendations for anything that will be used in a production setting or will be used by anyone that relies on it's cryptograhic properties, it is highly recommended to let your concept and implementation being reviewed by a reknown cybersecurity firm.

That being said, the author hopes that Cryptography Primer helps you find the correct algorithm to use for your scenario, and find the correct parameters and modes for a safe implementation.

On this page you will learn:

  • What is ChaCha, and features does it provide?
  • How secure is ChaCha?
  • What can I use instead of ChaCha?
  • What modes of operation can I use with ChaCha?

Quick Info

ChaCha
Names ChaCha (with various additions, see below)
Attributes Symmetric (Private Key), Stream Cipher
Features Encryption, AEAD
Private Key Size 256 Bits (32 Bytes)
First Published 2008

ChaCha in Practice

In practice, ChaCha is mostly used as the ChaCha20-Poly1305 variant, which is also recommended. The Private Key is always 256 Bits (32 Bytes). There are variations that trade security for speed by reducing the number of internal computation rounds: ChaCha12 and ChaCha8. We will not go into detail on these variants, because they are seldomly used.

ChaCha Key Generation

Private keys for ChaCha do not have to follow a specific form - they just need to be (crypto-secure) random bits of the required size. Other algorithms, such as RSA or EC, require the values to conform to some mathematical requirements, but ChaCha keys do not.

However, it is important to make sure that the key is generated properly, because otherwise the key generation can be an attack vector - and maybe even a very easy one to attack, if key generation is not "random enough".

Here are a few recommendations that you should keep in mind when implementing ChaCha key generation:

  • Use a CSPRNG (Cryptographically-secure Pseudo Random Number Generator) or HSM (Hardware Security Module), if possible
  • Otherwise make sure that you seed your random number generator properly (don't only use the current timestamp)
  • Always seed a key generator with new randomness - don't succinctly generate multiples keys from the same random number seed
  • Generate keys where they will be ultimately needed and stored - e.g. don't generate keys server-side to use them on the client, but generate them client-side instead.
  • Store private keys securely
  • Avoid transferring private keys
  • It is highly recommended to re-negotiate or rotate keys as often as possible. Don't see a Private Key as something "permanently" bound to a person or a node, but instead make it something ephemeral that can change on a frequent basis.

How to use passwords to encrypt/decrypt with ChaCha

Usually you use ChaCha in a manner that the key is derived from the password that a user has to enter to encrypt/decrypt the data. Because the key is of fixed length (256 Bits, which are 32 Bytes), you can not use the password as the key directly, because that would impose insecure and inpractical constraints on the password that the user has to choose.

Instead, a key derivation function is used to create an ChaCha-compatible key from a password. PBKDF2 (Password Based Key Derivation Function 2) is a state of the art key derivation function.

TODO: See the code sample below.

Modes of operation

ChaCha is a Stream Cipher, which means that it can encode arbitrary length of data - in contrast to Block Ciphers, which need "modes of operation" that help concatenate and pad data so that it fits into multiple of the Block Cipher's block size.

So ChaCha can be used "raw" as it is, in theory. But in practice, you should use ChaCha together with a MAC to achieve AEAD to make the cipher resitant to CCA. By far the most common MAC used with ChaCha is Poly1305, which makes ChaCha20-Poly1305 the most common incarnation of ChaCha nowadays.

Cipher Description
XChaCha20-Poly1305

Recommended

This is basically the same as ChaCha20-Poly1305, but uses a larger nonce of 192 Bit (24 Bytes). Because nonce-reuse12 is the point of an implementation that can go wrong easiest, XChaCha20-Poly1305 offers more "ease of implementation", because it makes it practically feasible to use random numbers as nonces easily. Other than that, the security attributes are equal to ChaCha20-Poly1305

ChaCha20-Poly1305

Recommended if you can't use XChaCha20-Poly1305

ChaCha20-Poly1305 is a very common Stream Cipher that is considered secure. It is widely deployed, studied and very fast. Because it uses a smaller nonce than XChaCha20-Poly1305, the dangers of accidental nonce-reuse12 is higher, which makes it a bit more error prone. Other than that, the security attributes are equal to XChaCha20-Poly1305.

ChaCha20

Use ChaCha20-Poly1305 instead

Raw ChaCha20 without authentication is not recommended, because there is usually no reason not to use ChaCha20-Poly1305 instead.

ChaCha12

Use only combined with authentication

While the reduction of the rounds might not impose practically weaker security10, there is no common or standardized cipher that uses ChaCha12 with authentication, which is why you should use XChaCha20-Poly1305 or ChaCha20-Poly1305 instead, if feasible. If you require the higher throughput/faster speed that ChaCha12 provides, you need to apply Encrypt-then-MAC11

ChaCha8

Use only combined with authentication

While the reduction of the rounds might not impose practically weaker security10, there is no common or standardized cipher that uses ChaCha8 with authentication, which is why you should use XChaCha20-Poly1305 or ChaCha20-Poly1305 instead, if feasible. If you require the higher throughput/faster speed that ChaCha8 provides, you need to apply Encrypt-then-MAC11

Security Recommendations

Recommended Discouraged
  • Use ChaCha20-Poly1305.
  • Use a key derivation function such as PBKDF2 to convert a password into an ChaCha-compatible key.
  • When you need asymmetric encryption (e.g. sender and receiver can not share a password and can not use a key exchange algorithm), use ChaCha20 together with RSA and encrypt the ChaCha-key using the RSA public key.TODO: Create a page with detailed instructions
  • It is very important that you don't use the same nonce multiple times with the same key.
  • Don't use raw ChaCha ciphers (e.g. without Poly1305). (detailed explanation on Tony Arcieri's blog)
  • Don't trust your crypto library's defaults - check that you are not accidentally use a discouraged practice, because your library has bad defaults.
  • Don't transmit the key between two parties. Either pre-share the key over a secure medium, use a key exchange algorithm (such as DH or ECDH) or an asymmetric encryption algorithm (such as RSA) for this.

Code Samples

ChaCha key generation

This code sample shows how to securely generate a new ChaCha key:

Warning

Do not use your regular "random" function for key generation, but use your crypto library's dedicated functions for this.

Info

This code sample requires the widely used pyca/cryptography package.

Install it with pip install cryptography or your favorite package manager.

from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305

# Generate a random 256 Bit private key:
key = ChaCha20Poly1305.generate_key()
print(key.hex())
// TODO
// TODO

Key derivation from passwords

This code sample show how to securely derive an encryption key from a password:

Info

This code sample requires the widely used pyca/cryptography package.

Install it with pip install cryptography or your favorite package manager.

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

# Salts should be randomly generated and need to be accessible
# whenever a key is derived from a password. So basically,
# the salt is usually stored/transmitted alongside the encrypted data.

salt = bytes.fromhex('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') # EXAMPLE VALUE - DO NOT USE THIS!

# derive
kdf = PBKDF2HMAC(
    algorithm=hashes.SHA256(),
    length=32, # 32 Bytes = 256 Bits
    salt=salt,
    iterations=100000, # This should be the minimum. You can increase the iterations if your system can handle it
                       # to strengthen security.
)
key = kdf.derive(b"my great password")
print(key.hex())

# `key` can now be used with ChaCha20-Poly1305
// TODO
// TODO

ChaCha20-Poly1305 encryption and decryption

Here's a code sample on a simple use case to encrypt and decrypt data:

Info

This code sample requires the widely used pyca/cryptography package.

Install it with pip install cryptography or your favorite package manager.

import os
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305

# The text to be encrypted:
plaintext = b"I am secret"

# Can be None, when no associated data is required:
authenticated_text= b"authenticated but unencrypted data"

# Generate a random private key for this example:
key = ChaCha20Poly1305.generate_key()

# Create an object that can encrypt/decrypt with the ChaCha20-Poly1305 AEAD cipher:
chacha = ChaCha20Poly1305(key)

# Generate a "nonce" for this encryption session of size 96 Bits (12 Bytes).
# A nonce ensures that the same plaintext is not encrypted to the same ciphertext, which strenghtens security:

nonce = os.urandom(12)
# Notice: NEVER re-use the same nonce with the same key. Using a counter - if feasible - is an appropriate
# way to prevent this. Using a random number might have a realistic chance of reuse,
# depending on the number of messages that are being encrypted, the implementation of the random number generator
# and the available entropy in the system.

# Encrypt the data and add the authenticated (but not encrypted) data:
ciphertext = chacha.encrypt(nonce, plaintext, authenticated_text)

# The content of "ciphertext" can now be shared via an untrusted medium.
# The receiver also needs to know the "nonce" and the authenticated text (when used),
# which can also be shared via an untrusted medium.

# Decrypt the ciphertext back into the plaintext:
plaintxt = chacha.decrypt(nonce, ciphertext, authenticated_text)

print(plaintext)

# Result: "I am secret"
// TODO
// TODO

Security Level

"Security Level" explained

In cryptography, anything that lets you decrypt a message or extract the secret key with less effort than "brute force" is considered a "break" or a possible "attack". "Brute force" means testing out the key in the whole key space - for 128 Bits (like in AES-128) this means trying all 340,282,366,920,938,463,463,374,607,431,768,211,456 possible values that an 128 Bit (16 Bytes) value can have. For 256 Bits (like in ChaCha20 or AES-256), these are 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,936 possible values.

As you can imagine, not every "attack" is a real problem. Having an attacker have to try out for example 2127 values (instead of 2128) is not a risk in practice.

With the help of certain "attacks" it is possible to reduce the key space required to try out in order to break the encryption. The lowest key space that you can attain for a given cipher using one or a combination of attacks is considered the "security level".

In cryptography, a key space of 280 (this is a security level of 80 Bits) has long been considered secure. This might no longer be the case, depending on how strong your security needs to be. The BSI (German Institute of Cybersecurity) recommends a security level of at least 100 Bits and even 120 Bits for high security[^10] in 2022.

The security level of a cipher is not fix in time. It might become lower if attacks on the cipher have been found. That is why security recommendations are valid usually not more than one or two years into the future.

In 2022, ChaCha20 is considered to have a full security level of 256 Bits, which is it's original Key Size. To quote the report8 "Security Analysis of ChaCha20-Poly1305 AEAD" from KDDI Research:

Quote

Therefore, we conclude that we cannot find any weaknesses in ChaCha20-Poly1305 AEAD.

What does it mean when a cipher is "broken"?

In cryptanalysis, which is the science of analysing and breaking cryptographic primitives, a cipher is "broken" if a way is found to decrypt the ciphertext or find the Private Key in less rounds than a brute force attack, which means trying all possible values in the Private Key's key space.

In practice, not every cipher that is "broken" by the definition of cryptanalysis is indeed insecure. For example, for AES a technique was found to reduce the theoretic maximum key space of 256 Bits down to 254 Bits. Because this reduced key space is still large enough for modern encryption requirements, AES is still very secure, although you might find statements that it has been "broken".

Variation Security Level Considered Secure?
ChaCha20 256 Bits :fontawesome-solid-check-circle:
ChaCha12 256 Bits :fontawesome-solid-check-circle:
ChaCha8 256 Bits :fontawesome-solid-check-circle:

The smaller variants of ChaCha, namely ChaCha12 and ChaCha8 might have weaker security than ChaCha20, but no practical attacks10 are known, yet. Even the smallest round variant, ChaCha8, is considered secure. The safest that cryptanalysis got in 2022 is reducing the Security Level of a reduced variant of ChaCha with 7 rounds, which you will not find implemented in your crypto library, to (maybe, this is a bit unclear) 237.7 Bits7.

Alternatives

Other Symmetric Encryption algorithms are:

Overview of encryption algorithms

Algorithm Key Sizes Type Authentication?
(AE or AEAD)
Recommendation
AES 128, 192 or 256 Bits

Symmetric

128 Bit Block Cipher

via GCM mode

Recommended

This algorithm is considered very secure and widely studied and deployed. GCM or CBC modes are recommended.

ChaCha 256 Bits

Symmetric

Stream Cipher

via Poly1305

Recommended

ChaCha20 is considered very secure and is widely studied and deployed. Use of Poly1305 is recommended.

RSA >= 1028 Bits

Asymmetric

Block Cipher
?

Recommended

This algorithm is considered very secure. Usually used with an symmetric encryption algorithm, while RSA "only" encrypts the symmetric key.

ECIES 256 Bits

Asymmetric (Hybrid)

Block Cipher or Stream Cipher possible
?

Recommended (but can be hard to implement)

This encryption scheme is considered very secure. It is not a precicse defined algorithm, but instead a framework to implement encryption when knowing the receiver's Elliptic Curve public key. It can be used with symmetric encryption algorithms (recommended: AES or ChaCha20).

Camellia 128, 192 or 256 Bits

Symmetric

Block Cipher

Considered secure

This algorithm is considered secure, but is not as widely studied or deployed as AES or ChaCha20

3DES 112 or 168 Bits

Symmetric

64 Bit Block Cipher

Less secure than AES and ChaCha20

This algorithm is not inherently insecure, but it is less secure than AES or ChaCha20, and computationally more expensive.

DES 56 Bits

Symmetric

64 Bit Block Cipher

Not recommended

This algorithm is no longer considered secure

Blowfish 32-448 Bits Symmetric 64 Bit Block Cipher

Not recommended

This algorithm is no longer considered secure

ARC4

(aka "RC4")
40-2048 Bits Symmetric Stream Cipher

Not recommended

This algorithm is no longer considered secure

IDEA 128 Bits Symmetric 64 Bit Block Cipher

Not recommended

This algorithm is no longer considered secure

History

Year Event
2008 First published by D. J. Bernstein9

References


  1. arXiv.org e-Print archive 

  2. Cryptography Stack Exchange 

  3. Information Security Stack Exchange 

  4. BSI - Cryptography on bsi.bund.de 

  5. NIST Computer Security Resource Center on nist.gov 

  6. TODO: Find a reference that recognizes ChaCha20-Poly1305 as secure 

  7. Analysis of Salsa, ChaCha, and Rumba by Jean-Philippe Aumasson, Simon Fischer, Shahram Khazaei, Willi Meier, and Christian Rechberger on eprint.iacr.org 

  8. Security Analysis of ChaCha20-Poly1305 AEAD by KDDI Research, Inc. on cryptrec.go.jp 

  9. The ChaCha family of stream ciphers by D. J. Bernstein on cr.yp.to 

  10. Too Much Crypto by Jean-Philippe Aumasson on eprint.iacr.org 

  11. Should we MAC-then-encrypt or encrypt-then-MAC? 

  12. Nonce reuse in encryption - what’s the worst that can happen? by Christian Lundkvist on github.com