ChaCha
This algorithm is recommended
Use ChaCha in it's XChaCha20Poly1305 or ChaCha20Poly1305 variations.
XChaCha20Poly1305 and ChaCha20Poly1305 are considered secure^{6} 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 AES256GCM, the differences in security to ChaCha20Poly1305 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.org^{1}
 Recommendations of Cryptographic Library authors
 BSI technical guidelines^{4}
 NIST publications^{5}
 Blogs of reknown cryptographers or cybersecurity experts
 crypto.stackexchange.com^{2}
 security.stackexchange.com^{3}
 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 ChaCha20Poly1305 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 (cryptosecure) 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 (Cryptographicallysecure 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 serverside to use them on the client, but generate them clientside instead.
 Store private keys securely
 Avoid transferring private keys
 It is highly recommended to renegotiate 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 ChaChacompatible 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 ChaCha20Poly1305 the most common incarnation of ChaCha nowadays.
Cipher  Description 

XChaCha20Poly1305  Recommended This is basically the same as ChaCha20Poly1305, but uses a larger nonce of 192 Bit (24 Bytes). Because noncereuse^{12} is the point of an implementation that can go wrong easiest, XChaCha20Poly1305 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 ChaCha20Poly1305 
ChaCha20Poly1305  Recommended if you can't use XChaCha20Poly1305 ChaCha20Poly1305 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 XChaCha20Poly1305, the dangers of accidental noncereuse^{12} is higher, which makes it a bit more error prone. Other than that, the security attributes are equal to XChaCha20Poly1305. 
ChaCha20  Use ChaCha20Poly1305 instead Raw ChaCha20 without authentication is not recommended, because there is usually no reason not to use ChaCha20Poly1305 instead. 
ChaCha12  Use only combined with authentication While the reduction of the rounds might not impose practically weaker security^{10}, there is no common or standardized cipher that uses ChaCha12 with authentication, which is why you should use XChaCha20Poly1305 or ChaCha20Poly1305 instead, if feasible. If you require the higher throughput/faster speed that ChaCha12 provides, you need to apply EncryptthenMAC^{11} 
ChaCha8  Use only combined with authentication While the reduction of the rounds might not impose practically weaker security^{10}, there is no common or standardized cipher that uses ChaCha8 with authentication, which is why you should use XChaCha20Poly1305 or ChaCha20Poly1305 instead, if feasible. If you require the higher throughput/faster speed that ChaCha8 provides, you need to apply EncryptthenMAC^{11} 
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 ChaCha20Poly1305
// TODO
// TODO
ChaCha20Poly1305 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 ChaCha20Poly1305 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 reuse 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 AES128) 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 AES256), 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 2^{127} values (instead of 2^{128}) 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 2^{80} (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 report^{8} "Security Analysis of ChaCha20Poly1305 AEAD" from KDDI Research:
Quote
Therefore, we conclude that we cannot find any weaknesses in ChaCha20Poly1305 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  :fontawesomesolidcheckcircle: 
ChaCha12  256 Bits  :fontawesomesolidcheckcircle: 
ChaCha8  256 Bits  :fontawesomesolidcheckcircle: 
The smaller variants of ChaCha, namely ChaCha12 and ChaCha8 might have weaker security than ChaCha20, but no practical attacks^{10} 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 Bits^{7}.
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  32448 Bits  Symmetric 64 Bit Block Cipher  ❌  Not recommended This algorithm is no longer considered secure 
ARC4 (aka "RC4") 
402048 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. Bernstein^{9} 
References

BSI  Cryptography on bsi.bund.de ↩

NIST Computer Security Resource Center on nist.gov ↩

TODO: Find a reference that recognizes ChaCha20Poly1305 as secure ↩

Analysis of Salsa, ChaCha, and Rumba by JeanPhilippe Aumasson, Simon Fischer, Shahram Khazaei, Willi Meier, and Christian Rechberger on eprint.iacr.org ↩

Security Analysis of ChaCha20Poly1305 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 JeanPhilippe Aumasson on eprint.iacr.org ↩↩↩

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