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 |
---|---|
|
|
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
-
BSI - Cryptography on bsi.bund.de ↩
-
NIST Computer Security Resource Center on nist.gov ↩
-
TODO: Find a reference that recognizes ChaCha20-Poly1305 as secure ↩
-
Analysis of Salsa, ChaCha, and Rumba by Jean-Philippe Aumasson, Simon Fischer, Shahram Khazaei, Willi Meier, and Christian Rechberger on eprint.iacr.org ↩
-
Security Analysis of ChaCha20-Poly1305 AEAD by KDDI Research, Inc. on cryptrec.go.jp ↩
-
The ChaCha family of stream ciphers by D. J. Bernstein on cr.yp.to ↩
-
Too Much Crypto by Jean-Philippe Aumasson on eprint.iacr.org ↩↩↩
-
Nonce reuse in encryption - what’s the worst that can happen? by Christian Lundkvist on github.com ↩↩