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