ChaCha20#

How to use the crypto_condor.primitives.ChaCha20 module to test implementations of ChaCha20.

Supported parameters#

There are two supported modes of operation: ChaCha20 on its own and the construction with Poly1305. They are defined by the Mode enum.

Two operations can be performed: ENCRYPT and DECRYPT. These are defined by the Operation enum.

enum crypto_condor.primitives.ChaCha20.Mode(value)#

Supported ChaCha20 modes of operation.

Member Type:

str

Valid values are as follows:

CHACHA20_POLY1305 = <Mode.CHACHA20_POLY1305: 'CHACHA20-POLY1305'>#
CHACHA20 = <Mode.CHACHA20: 'CHACHA20'>#
enum crypto_condor.primitives.ChaCha20.Operation(value)#

Supported operations.

Member Type:

str

Valid values are as follows:

ENCRYPT = <Operation.ENCRYPT: 'encrypt'>#
DECRYPT = <Operation.DECRYPT: 'decrypt'>#

Test an implementation directly#

crypto_condor.primitives.ChaCha20.test(encrypt, decrypt, mode, *, resilience=True)#

Tests an implementation of ChaCha20(-Poly1305) encryption and decryption.

It runs test vectors on the given functions. These functions must conform to the Encrypt and Decrypt protocols.

Parameters:
  • encrypt (Encrypt | None) – The encryption function to test. Using None skips this test.

  • decrypt (Decrypt | None) – The decryption function to test. Using None skips this test.

  • mode (Mode) – The mode of operation to test.

Keyword Arguments:

resilience – If True, runs Wycheproof test vectors.

Returns:

A dictionary of results.

If resilience is True, Wycheproof vectors are used. The results are indexed by Wycheproof/encrypt and Wycheproof/decrypt respectively.

Return type:

ResultsDict

Example

Let’s test PyCryptodome’s implementation of ChaCha20.

We start by importing the ChaCha20 modules of crypto-condor and PyCryptodome.

>>> from crypto_condor.primitives import ChaCha20
>>> from Crypto.Cipher import ChaCha20 as pyChaCha20

We need to wrap PyCryptodome’s to match the signature of Encrypt and Decrypt. In both cases we want to match the first overload, as it is the one that corresponds to ChaCha20.

>>> def my_enc(
...     key: bytes,
...     plaintext: bytes,
...     nonce: bytes,
...     *,
...     init_counter: int = 0
... ) -> bytes:
...     cipher = pyChaCha20.new(key=key, nonce=nonce)
...     if init_counter > 0:
...         cipher.seek(64 * init_counter)
...     return cipher.encrypt(plaintext)
>>> def my_dec(
...     key: bytes,
...     ciphertext: bytes,
...     nonce: bytes,
...     *,
...     init_counter: int = 0
... ) -> bytes:
...     cipher = pyChaCha20.new(key=key, nonce=nonce)
...     if init_counter > 0:
...         cipher.seek(64 * init_counter)
...     return cipher.decrypt(ciphertext)

And we test the functions we defined.

>>> mode = ChaCha20.Mode.CHACHA20
>>> results_dict = ChaCha20.test(my_enc, my_dec, mode)
[Wycheproof] ...
>>> assert results_dict.check()

Test the output of an implementation#

Note

From the CLI you can test the file with the test output ChaCha20 command.

crypto_condor.primitives.ChaCha20.verify_file(filename, mode, operation)#

Tests the output of an implementation.

Tests an implementation from a set of inputs passed to it and the outputs it returned. These inputs are passed to the internal implementation and the results are compared to the outputs given.

Format:
  • One line per operation.

  • Lines are separated by newlines (\n).

  • Lines that start with # are counted as comments and ignored.

  • Arguments written in hexadecimal and separated by slashes.

  • Arguments in brackets are optional. If omitted, don’t include the trailing slash.

  • For ChaCha20, the order of the arguments is:

key/input/output/nonce[/init_counter]
  • For ChaCha20-Poly1305, the order of the arguments is:

key/input/output/nonce/mac[/aad]
  • Where:
    • input is the plaintext when encrypting (resp. the ciphertext when decrypting).

    • output is the ciphertext when encrypting (resp. the plaintext when decrypting).

    • nonce is the nonce used for that operation.

    • init_counter is the initial position in the keystream to seek before the operation.

    • mac is the MAC tag. When encrypting, it is compared to the MAC returned by the internal implementation. When decrypting it is used to authenticate the ciphertext.

    • aad is the associated data. Can be empty.

Parameters:
  • filename (str) – The name of the file to test.

  • mode (Mode) – The mode of operation to use.

  • operation (Operation) – The operation being tested, ‘encrypt’ or ‘decrypt’.

Returns:

The results of running the inputs of each line with the internal implementation, and comparing both outputs to see if they match.

Parsing errors are considered as test failures.

Return type:

Results

Example

Let’s generate 10 random tuples of (key, plaintext, nonce), encrypt the plaintexts using PyCryptodome, and write everything to a file.

>>> import random
>>> from crypto_condor.primitives import ChaCha20
>>> from Crypto.Cipher import ChaCha20 as pyChaCha20
>>> filename = "/tmp/crypto-condor-test/chacha20-verify.txt"
>>> with open(filename, "w") as file:
...     for _ in range(10):
...         # Pick random values
...         key = random.randbytes(32)
...         plaintext = random.randbytes(64)
...         nonce = random.randbytes(12)
...         # Encrypt
...         cipher = pyChaCha20.new(key=key, nonce=nonce)
...         ciphertext = cipher.encrypt(plaintext)
...         # Convert to hexadecimal
...         kh, nh = key.hex(), nonce.hex()
...         ph, ch = plaintext.hex(), ciphertext.hex()
...         # Create the line to write, note the absent init_counter
...         line = f"{kh}/{ph}/{ch}/{nh}\n"
...         _ = file.write(line)

Now we can test the file.

>>> mode = ChaCha20.Mode.CHACHA20
>>> operation = ChaCha20.Operation.ENCRYPT
>>> results = ChaCha20.verify_file(filename, mode, operation)
Testing ...
>>> assert results.check()

Run a wrapper#

Note

Available wrappers are defined by the Wrapper enum.

crypto_condor.primitives.ChaCha20.run_wrapper(language, mode, *, resilience=True, encrypt=True, decrypt=True)#

Runs a wrapper.

Parameters:
  • language (Wrapper) – The language of the wrapper.

  • mode (Mode) – The mode of operation to test.

Keyword Arguments:
  • resilience – Whether to run resilience test vectors.

  • encrypt – Whether to test the encryption.

  • decrypt – Whether to test the decryption.

Returns:

The results from test().

Return type:

ResultsDict

enum crypto_condor.primitives.ChaCha20.Wrapper(value)#

Supported wrapper languages.

Member Type:

str

Valid values are as follows:

PYTHON = <Wrapper.PYTHON: 'Python'>#

Protocols#

protocol crypto_condor.primitives.ChaCha20.Encrypt#

Represents a function that encrypts with ChaCha20.

Encryption functions must behave like one of the __call__() overloads below to be tested with this module. The first corresponds to ChaCha20, the second to ChaCha20-Poly1305.

Classes that implement this protocol must have the following methods / attributes:

__call__(key: bytes, plaintext: bytes, nonce: bytes, *, init_counter: int = 0) bytes#
__call__(key: bytes, plaintext: bytes, nonce: bytes, *, aad: bytes | None) CiphertextAndTag

Encrypts with ChaCha20(-Poly1305).

Parameters:
  • key – The symmetric key.

  • plaintext – The message to encrypt.

  • nonce – The nonce to use for this message.

Keyword Arguments:
  • init_counter – (ChaCha20 only) A position to seek in the keystream before encrypting, in bytes.

  • aad – (ChaCha20-Poly1305 only) The associated data, can be empty or None.

Returns:

(ChaCha20) The ciphertext.

(ChaCha20-Poly1305) A (ciphertext, MAC) tuple.

protocol crypto_condor.primitives.ChaCha20.Decrypt#

Represents a function that decrypts with ChaCha20.

Decryption functions must behave like one of the __call__() overloads below to be tested with this module. The first corresponds to ChaCha20, the second to ChaCha20-Poly1305.

Classes that implement this protocol must have the following methods / attributes:

__call__(key: bytes, ciphertext: bytes, nonce: bytes, *, init_counter: int = 0) bytes#
__call__(key: bytes, ciphertext: bytes, nonce: bytes, *, mac: bytes, aad: bytes | None) PlaintextAndBool

Decrypts with ChaCha20(-Poly1305).

Parameters:
  • key – The symmetric key.

  • ciphertext – The message to decrypt.

  • nonce – The nonce to use for this message.

Keyword Arguments:
  • init_counter – (ChaCha20 only) A position to seek in the keystream before encrypting, in bytes.

  • mac – (ChaCha20-Poly1305 only) The MAC tag to use for authenticating the ciphertext.

  • aad – (ChaCha20-Poly1305 only) The associated data, can be empty or None.

Returns:

(ChaCha20) The plaintext.

(ChaCha20-Poly1305) If the MAC is valid, a (plaintext, True) tuple. Otherwise the plaintext should not be released, so return a (None, False) tuple.