1ChaCha20 and XChaCha20
2======================
3
4`ChaCha20`_ is a stream cipher designed by Daniel J. Bernstein.
5The secret key is 256 bits long (32 bytes).
6The cipher requires a nonce, which **must not** be reused
7across encryptions performed with the same key.
8
9There are three variants, defined by the length of the nonce:
10
11.. csv-table::
12    :header: Nonce length, Description, Max data, If random nonce and same key
13    :widths: 5, 50, 20, 20
14
15    "8 bytes (default)", "The original ChaCha20 designed by Bernstein.", "No limitations", "Max 200 000 messages"
16    "12 bytes", "The TLS ChaCha20 as defined in `RFC7539`_.", "256 GB", "Max 13 billions messages"
17    "24 bytes", "XChaCha20, still in `draft stage <https://tools.ietf.org/html/draft-arciszewski-xchacha-03>`_.", "256 GB", "No limitations"
18
19.. see probability p=10⁻⁶ in table https://en.wikipedia.org/wiki/Birthday_problem#Probability_table
20
21This is an example of how `ChaCha20`_ (Bernstein's version) can encrypt data::
22
23    >>> import json
24    >>> from base64 import b64encode
25    >>> from Crypto.Cipher import ChaCha20
26    >>> from Crypto.Random import get_random_bytes
27    >>>
28    >>> plaintext = b'Attack at dawn'
29    >>> key = get_random_bytes(32)
30    >>> cipher = ChaCha20.new(key=key)
31    >>> ciphertext = cipher.encrypt(plaintext)
32    >>>
33    >>> nonce = b64encode(cipher.nonce).decode('utf-8')
34    >>> ct = b64encode(ciphertext).decode('utf-8')
35    >>> result = json.dumps({'nonce':nonce, 'ciphertext':ct})
36    >>> print(result)
37    {"nonce": "IZScZh28fDo=", "ciphertext": "ZatgU1f30WDHriaN8ts="}
38
39And this is how you decrypt it::
40
41    >>> import json
42    >>> from base64 import b64decode
43    >>> from Crypto.Cipher import ChaCha20
44    >>>
45    >>> # We assume that the key was somehow securely shared
46    >>> try:
47    >>>     b64 = json.loads(json_input)
48    >>>     nonce = b64decode(b64['nonce'])
49    >>>     ciphertext = b64decode(b64['ciphertext'])
50    >>>     cipher = ChaCha20.new(key=key, nonce=nonce)
51    >>>     plaintext = cipher.decrypt(ciphertext)
52    >>>     print("The message was " + plaintext)
53    >>> except ValueError, KeyError:
54    >>>     print("Incorrect decryption")
55
56In order to have a `RFC7539`_-compliant ChaCha20 cipher,
57you need to explicitly generate and pass a 96 bit (12 byte) ``nonce`` parameter to ``new()``::
58
59    nonce_rfc7539 = get_random_bytes(12)
60    cipher = ChaCha20.new(key=key, nonce=nonce_rfc7539)
61
62.. warning::
63
64    ``ChaCha20`` does not guarantee authenticity of the data you decrypt!
65    In other words, an attacker may manipulate the data in transit.
66    In order to prevent that, you must also use a *Message Authentication
67    Code* (such as :doc:`HMAC <../hash/hmac>`) to authenticate the ciphertext
68    (*encrypt-then-mac*). Alternatively, you can use :doc:`ChaCha20_Poly1305 <chacha20_poly1305>`.
69
70.. _ChaCha20: http://http://cr.yp.to/chacha.html
71.. _RFC7539: https://tools.ietf.org/html/rfc7539
72
73.. automodule:: Crypto.Cipher.ChaCha20
74    :members:
75