CRYPTO_CHACHA20(3MONOCYPHER) | 3MONOCYPHER | CRYPTO_CHACHA20(3MONOCYPHER) |
crypto_chacha20
,
crypto_chacha20_ctr
,
crypto_xchacha20
,
crypto_xchacha20_ctr
—
#include <monocypher.h>
void
crypto_chacha20
(uint8_t
*cipher_text, const uint8_t *plain_text,
size_t text_size, const uint8_t
key[32], const uint8_t nonce[8]);
void
crypto_xchacha20
(uint8_t
*cipher_text, const uint8_t *plain_text,
size_t text_size, const uint8_t
key[32], const uint8_t nonce[24]);
uint64_t
crypto_chacha20_ctr
(uint8_t
*cipher_text, const uint8_t *plain_text,
size_t text_size, const uint8_t
key[32], const uint8_t nonce[8],
uint64_t ctr);
uint64_t
crypto_xchacha20_ctr
(uint8_t
*cipher_text, const uint8_t *plain_text,
size_t text_size, const uint8_t
key[32], const uint8_t nonce[24],
uint64_t ctr);
ChaCha20 is a low-level primitive. Consider using authenticated encryption, implemented by crypto_lock(3monocypher).
The arguments are:
NULL
,
in which case it will be interpreted as an all-zero input.
cipher_text will then contain the raw ChaCha20
stream.The key and nonce buffers may overlap. plain_text and cipher_text must either be the same buffer (for in-place encryption) or non-overlapping.
crypto_chacha20
() performs a ChaCha20
operation. It uses an 8-byte nonce, which is too small to be selected at
random. Use a message counter as a nonce instead.
crypto_xchacha20
() performs an XChaCha20
operation. It uses a 24-byte nonce, which is large enough to be selected at
random.
crypto_xchacha20
() is recommended over
crypto_chacha20
(). The ability to use random nonces
makes it easier to use securely, and the performance hit is often negligible
in practice.
The crypto_chacha20
() and
crypto_xchacha20
() encrypt
plain_text by XORing it with a pseudo-random stream of
numbers, seeded by the provided key and
nonce.
Since XOR is its own inverse, decryption is the same operation as encryption. To decrypt the cipher text, “encrypt” it again with the same key and nonce. You will likely want to wipe the key when you are done with encryption or decryption. Use crypto_wipe(3monocypher) to wipe them.
The plain_text pointer is allowed to be
NULL
, in which case it will be interpreted as an
all-zero input. This is useful as a user space random number generator.
While this should not be used as a random number generator for
secrets, for which the operating system random number generator should
be preferred, it can be handy outside of a security context. Deterministic
procedural generation and reproducible property-based tests come to mind.
Additionally, it can be used to generate large amounts of
random-looking data quickly – for example to generate padding.
The crypto_chacha20_ctr
() and
crypto_xchacha20_ctr
() perform ChaCha20 or XChaCha20
encryption, starting the stream at the block ctr
(which is the byte ‘ctr × 64
’).
This can be used to encrypt (or decrypt) part of a long message or to
implement some AEAD constructions such as the one described in RFC 8439.
When using this, be careful not to accidentally reuse parts of the random
stream as that would destroy confidentiality.
crypto_chacha20
() and
crypto_xchacha20
() return nothing.
crypto_chacha20_ctr
() and
crypto_xchacha20_ctr
() functions return the next
ctr to use with the same key and nonce values; this is
always text_size divided by 64, plus one if there was a
remainder.
arc4random_buf
(), which fills the given buffer with
cryptographically secure random bytes. If
arc4random_buf
() does not exist on your system, see
intro(3monocypher) for advice about how to
generate cryptographically secure random bytes.
Simple encryption:
uint8_t key [ 32]; /* Secret random key */ uint8_t nonce [ 24]; /* Unique nonce (possibly random) */ uint8_t plain_text [500] = {1}; /* Secret message */ uint8_t cipher_text[500]; /* Encrypted message */ arc4random_buf(key, 32); arc4random_buf(nonce, 24); crypto_xchacha20(cipher_text, plain_text, 500, key, nonce); /* Wipe secrets if they are no longer needed */ crypto_wipe(key, 32); crypto_wipe(plain_text, 500);
To decrypt the above:
uint8_t key [ 32]; /* Same key as above */ const uint8_t nonce [ 24]; /* Same nonce as above */ uint8_t plain_text [500]; /* Message to decrypt */ uint8_t cipher_text[500]; /* Secret message */ crypto_xchacha20(cipher_text, plain_text, 500, key, nonce); /* Wipe secrets if they are no longer needed */ crypto_wipe(key, 32); /* The plaintext likely needs to be processed before you wipe it */ crypto_wipe(plain_text, 12);
Incremental encryption (in blocks of 64 bytes):
uint8_t key [ 32]; /* Secret random key */ uint8_t nonce [ 24]; /* Unique nonce (possibly random) */ uint8_t plain_text [500]; /* Secret message */ uint8_t cipher_text[500]; /* Encrypted message */ uint64_t ctr = 0; /* Block counter */ unsigned int i; arc4random_buf(key, 32); arc4random_buf(nonce, 24); for(i = 0; i < 500; i += 64) { ctr = crypto_xchacha20_ctr(cipher_text+i, plain_text+i, 64, key, nonce, ctr); } /* Process data that didn't fit into 64-byte pieces */ crypto_xchacha20_ctr(cipher_text+500-(i-64), plain_text+500-(i-64), 500-(i-64), key, nonce, ctr); /* Wipe secrets if they are no longer needed */ crypto_wipe(key, 32); crypto_wipe(plain_text, 500);
Encryption by jumping around (do not do this, this is only meant
to show how crypto_xchacha20_ctr
() works):
uint8_t key [ 32]; /* Secret random key */ uint8_t nonce [ 24]; /* Unique nonce (possibly random) */ uint8_t plain_text [500] = {1}; /* Message to be encrypted */ uint8_t cipher_text[500]; /* Will be the encrypted message */ arc4random_buf(key, 32); arc4random_buf(nonce, 24); /* Encrypt the second part of the message first... */ crypto_xchacha20_ctr(cipher_text + (3 * 64), plain_text + (3 * 64), 500 - (3 * 64), key, nonce, 3); /* ...then encrypt the first part */ crypto_xchacha20_ctr(cipher_text, plain_text, 3 * 64, key, nonce, 0); /* Wipe secrets if they are no longer needed */ crypto_wipe(key, 32); crypto_wipe(plain_text, 500);
crypto_chacha20
(),
crypto_chacha20_ctr
(),
crypto_xchacha20
(), and
crypto_xchacha20_ctr
() were added in Monocypher 3.0.0.
They replace crypto_chacha20_encrypt
(),
crypto_chacha20_init
(),
crypto_chacha20_stream
(),
crypto_chacha20_x_init
(), and
crypto_chacha20_set_ctr
() that were deprecated in
Monocypher 3.0.0.
For the same reason, do not select small nonces at
random. The crypto_chacha20
() nonce spans only
64 bits, which is small enough to trigger accidental reuses. A message
counter should be used instead. If multiple parties send out messages, each
can start with an initial nonce of 0, 1, 2 (...) n-1 respectively, and
increment them by n for each new message. Make sure the counters never wrap
around.
June 11, 2021 | Debian |