# 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.

class Crypto.Cipher.ChaCha20.ChaCha20Cipher(key, nonce)

  ChaCha20 (or XChaCha20) cipher object. Do not create it directly. Use `new()` instead.

  Variables:

    nonce (bytes) – The nonce with length 8, 12 or 24 bytes

  decrypt(ciphertext, output=None)

    Decrypt a piece of data.

    Parameters:

      ciphertext (bytes/bytearray/memoryview) – The data to decrypt, of any size.

    Keyword Arguments:

      output (bytes/bytearray/memoryview) – The location where the plaintext is written to. If `None`, the plaintext is returned.

    Returns:

      If `output` is `None`, the plaintext is returned as `bytes`. Otherwise, `None`.

  encrypt(plaintext, output=None)

    Encrypt a piece of data.

    Parameters:

      plaintext (bytes/bytearray/memoryview) – The data to encrypt, of any size.

    Keyword Arguments:

      output (bytes/bytearray/memoryview) – The location where the ciphertext is written to. If `None`, the ciphertext is returned.

    Returns:

      If `output` is `None`, the ciphertext is returned as `bytes`. Otherwise, `None`.

  seek(position)

    Seek to a certain position in the key stream.

    Parameters:

      position (integer) – The absolute position within the key stream, in bytes.

Crypto.Cipher.ChaCha20.new(**kwargs)

  Create a new ChaCha20 or XChaCha20 cipher

  Keyword Arguments:

    - key (bytes/bytearray/memoryview) – The secret key to use. It must be 32 bytes long.

    - nonce (bytes/bytearray/memoryview) –

      A mandatory value that must never be reused for any other encryption done with this key.

      For ChaCha20, it must be 8 or 12 bytes long.

      For XChaCha20, it must be 24 bytes long.

      If not provided, 8 bytes will be randomly generated (you can find them back in the `nonce` attribute).

  Return:

    a `Crypto.Cipher.ChaCha20.ChaCha20Cipher` object