ChaCha20 and XChaCha20¶
ChaCha20 is a stream cipher designed by Daniel J. Bernstein. The secret key is 256 bits long (32 bytes). The cipher requires a nonce, which must not be reused across encryptions performed with the same key.
There are three variants, defined by the length of the nonce:
Nonce length |
Description |
Max data |
If random nonce and same key |
---|---|---|---|
8 bytes (default) |
The original ChaCha20 designed by Bernstein. |
No limitations |
Max 200 000 messages |
12 bytes |
The TLS ChaCha20 as defined in RFC7539. |
256 GB |
Max 13 billions messages |
24 bytes |
XChaCha20, still in draft stage. |
256 GB |
No limitations |
This is an example of how ChaCha20 (Bernstein’s version) can encrypt data:
>>> import json
>>> from base64 import b64encode
>>> from Crypto.Cipher import ChaCha20
>>> from Crypto.Random import get_random_bytes
>>>
>>> plaintext = b'Attack at dawn'
>>> key = get_random_bytes(32)
>>> cipher = ChaCha20.new(key=key)
>>> ciphertext = cipher.encrypt(plaintext)
>>>
>>> nonce = b64encode(cipher.nonce).decode('utf-8')
>>> ct = b64encode(ciphertext).decode('utf-8')
>>> result = json.dumps({'nonce':nonce, 'ciphertext':ct})
>>> print(result)
{"nonce": "IZScZh28fDo=", "ciphertext": "ZatgU1f30WDHriaN8ts="}
And this is how you decrypt it:
>>> import json
>>> from base64 import b64decode
>>> from Crypto.Cipher import ChaCha20
>>>
>>> # We assume that the key was somehow securely shared
>>> try:
>>> b64 = json.loads(json_input)
>>> nonce = b64decode(b64['nonce'])
>>> ciphertext = b64decode(b64['ciphertext'])
>>> cipher = ChaCha20.new(key=key, nonce=nonce)
>>> plaintext = cipher.decrypt(ciphertext)
>>> print("The message was " + plaintext)
>>> except (ValueError, KeyError):
>>> print("Incorrect decryption")
In order to have a RFC7539-compliant ChaCha20 cipher,
you need to explicitly generate and pass a 96 bit (12 byte) nonce
parameter to new()
:
nonce_rfc7539 = get_random_bytes(12)
cipher = ChaCha20.new(key=key, nonce=nonce_rfc7539)
Warning
ChaCha20
does not guarantee authenticity of the data you decrypt!
In other words, an attacker may manipulate the data in transit.
In order to prevent that, you must also use a Message Authentication
Code (such as HMAC) to authenticate the ciphertext
(encrypt-then-mac). Alternatively, you can use ChaCha20_Poly1305.