# ChaCha20-Poly1305 and XChaCha20-Poly1305

ChaCha20-Poly1305 is an authenticated cipher with associated data (AEAD). It works with a 32 byte secret key and a nonce which must never be reused across encryptions performed under the same key. The cipher produces a 16 byte tag that the receiver must use to validate the message.

There are three variants of the algorithm, defined by the length of the nonce:

Nonce length | Description | Max plaintext | If random nonce and same key
--- | --- | --- | ---
8 bytes | Based on Bernstein’s original ChaCha20. | No limitations | Max 200 000 messages
12 bytes (default) | Version used in TLS and specified in RFC7539. | 256 GB | Max 13 billion messages
24 bytes | XChaCha20-Poly1305, still in draft stage. | 256 GB | No limitations

The API of the cipher and its finite state machine are the same as for the modern modes of operation of block ciphers.

You create a new cipher by calling `Crypto.Cipher.ChaCha20_Poly1305.new()`.

This is an example of how ChaCha20-Poly1305 (TLS version) can encrypt and authenticate data:

    >>> import json
    >>> from base64 import b64encode
    >>> from Crypto.Cipher import ChaCha20_Poly1305
    >>> from Crypto.Random import get_random_bytes
    >>>
    >>> header = b"header"
    >>> plaintext = b'Attack at dawn'
    >>> key = get_random_bytes(32)
    >>> cipher = ChaCha20_Poly1305.new(key=key)
    >>> cipher.update(header)
    >>> ciphertext, tag = cipher.encrypt_and_digest(plaintext)
    >>>
    >>> jk = [ 'nonce', 'header', 'ciphertext', 'tag' ]
    >>> jv = [ b64encode(x).decode('utf-8') for x in (cipher.nonce, header, ciphertext, tag) ]
    >>> result = json.dumps(dict(zip(jk, jv)))
    >>> print(result)
    {"nonce": "4EE/9uqhoZ3mQXmm", "header": "aGVhZGVy", "ciphertext": "Wmmo4Vzn+eS3tUPv2a8=", "tag": "/FgVbM8qhzssPRY80T0iVA=="}

In the example above, a 96 bit (12 byte) nonce is automatically created. It can be accessed as the `nonce` member in the `cipher` object.

This is how you decrypt the data and check its authenticity:

    >>> import json
    >>> from base64 import b64decode
    >>> from Crypto.Cipher import ChaCha20_Poly1305
    >>>
    >>> # We assume that the key was securely shared beforehand
    >>> try:
    >>>     b64 = json.loads(json_input)
    >>>     jk = [ 'nonce', 'header', 'ciphertext', 'tag' ]
    >>>     jv = {k:b64decode(b64[k]) for k in jk}
    >>>
    >>>     cipher = ChaCha20_Poly1305.new(key=key, nonce=jv['nonce'])
    >>>     cipher.update(jv['header'])
    >>>     plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag'])
    >>>     print("The message was: " + plaintext)
    >>> except (ValueError, KeyError):
    >>>     print("Incorrect decryption")

class Crypto.Cipher.ChaCha20_Poly1305.ChaCha20Poly1305Cipher(key, nonce)

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

  Variables:

    nonce (byte string) – 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`.

  decrypt_and_verify(ciphertext, received_mac_tag)

    Perform `decrypt()` and `verify()` in one step.

    Parameters:

      - ciphertext (bytes/bytearray/memoryview) – The piece of data to decrypt.

      - received_mac_tag (bytes) – This is the 16-byte binary MAC, as received from the sender.

    Returns:

      the decrypted data (as `bytes`)

    Raises:

      ValueError – if the MAC does not match. The message has been tampered with or the key is incorrect.

  digest()

    Compute the binary authentication tag (MAC).

    Return:

      the MAC tag, as 16 `bytes`.

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

  encrypt_and_digest(plaintext)

    Perform `encrypt()` and `digest()` in one step.

    Parameters:

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

    Returns:

      a tuple with two `bytes` objects:

      - the ciphertext, of equal length as the plaintext

      - the 16-byte MAC tag

  hexdigest()

    Compute the printable authentication tag (MAC).

    This method is like `digest()`.

    Return:

      the MAC tag, as a hexadecimal string.

  hexverify(hex_mac_tag)

    Validate the printable authentication tag (MAC).

    This method is like `verify()`.

    Parameters:

      hex_mac_tag (string) – This is the printable MAC.

    Raises ValueError:

      if the MAC does not match. The message has been tampered with or the key is incorrect.

  update(data)

    Protect the associated data.

    Associated data (also known as additional authenticated data - AAD) is the piece of the message that must stay in the clear, while still allowing the receiver to verify its integrity. An example is packet headers.

    The associated data (possibly split into multiple segments) is fed into `update()` before any call to `decrypt()` or `encrypt()`. If there is no associated data, `update()` is not called.

    Parameters:

      assoc_data (bytes/bytearray/memoryview) – A piece of associated data. There are no restrictions on its size.

  verify(received_mac_tag)

    Validate the binary authentication tag (MAC).

    The receiver invokes this method at the very end, to check if the associated data (if any) and the decrypted messages are valid.

    Parameters:

      received_mac_tag (bytes/bytearray/memoryview) – This is the 16-byte binary MAC, as received from the sender.

    Raises ValueError:

      if the MAC does not match. The message has been tampered with or the key is incorrect.

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

  Create a new ChaCha20-Poly1305 or XChaCha20-Poly1305 AEAD cipher.

  Keyword Arguments:

    - key – The secret key to use. It must be 32 bytes long.

    - nonce –

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

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

      For XChaCha20-Poly1305, it must be 24 bytes long.

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

  Return:

    a `Crypto.Cipher.ChaCha20.ChaCha20Poly1305Cipher` object