.\" This file is dual-licensed. Choose whichever you want. .\" .\" The first licence is a regular 2-clause BSD licence. The second licence .\" is the CC-0 from Creative Commons. It is intended to release Monocypher .\" to the public domain. The BSD licence serves as a fallback option. .\" .\" SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0 .\" .\" ---------------------------------------------------------------------------- .\" .\" Copyright (c) 2017-2019, 2023 Loup Vaillant .\" Copyright (c) 2017-2018 Michael Savage .\" Copyright (c) 2017, 2019-2021, 2023 Fabio Scotoni .\" All rights reserved. .\" .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions are .\" met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the .\" distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE .\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" ---------------------------------------------------------------------------- .\" .\" Written in 2017-2023 by Loup Vaillant, Michael Savage and Fabio Scotoni .\" .\" To the extent possible under law, the author(s) have dedicated all copyright .\" and related neighboring rights to this software to the public domain .\" worldwide. This software is distributed without any warranty. .\" .\" You should have received a copy of the CC0 Public Domain Dedication along .\" with this software. If not, see .\" .\" .Dd February 25, 2023 .Dt CRYPTO_CHACHA20 3MONOCYPHER .Os .Sh NAME .Nm crypto_chacha20_djb , .Nm crypto_chacha20_ietf , .Nm crypto_chacha20_x , .Nm crypto_chacha20_h .Nd ChaCha20 and XChaCha20 encryption functions .Sh SYNOPSIS .In monocypher.h .Ft uint64_t .Fo crypto_chacha20_djb .Fa "uint8_t *cipher_text" .Fa "const uint8_t *plain_text" .Fa "size_t text_size" .Fa "const uint8_t key[32]" .Fa "const uint8_t nonce[8]" .Fa "uint64_t ctr" .Fc .Ft uint32_t .Fo crypto_chacha20_ietf .Fa "uint8_t *cipher_text" .Fa "const uint8_t *plain_text" .Fa "size_t text_size" .Fa "const uint8_t key[32]" .Fa "const uint8_t nonce[12]" .Fa "uint32_t ctr" .Fc .Ft uint64_t .Fo crypto_chacha20_x .Fa "uint8_t *cipher_text" .Fa "const uint8_t *plain_text" .Fa "size_t text_size" .Fa "const uint8_t key[32]" .Fa "const uint8_t nonce[24]" .Fa "uint64_t ctr" .Fc .Ft void .Fo crypto_chacha20_h .Fa "uint8_t out[32]" .Fa "const uint8_t key[32]" .Fa "const uint8_t in[16]" .Fc .Sh DESCRIPTION These functions provide an interface for the ChaCha20 encryption primitive. .Pp ChaCha20 is a low-level primitive. Consider using authenticated encryption, implemented by .Xr crypto_aead_lock 3monocypher . .Pp The arguments are: .Bl -tag -width Ds .It Fa key A 32-byte secret key. .It Fa nonce An 8-byte, 12-byte, or 24-byte number used only once with any given key. It does not need to be secret or random, but it does have to be unique. Repeating a nonce with the same key reveals the XOR of two different messages, which allows decryption. 24-byte nonces can be selected at random. 8-byte and 12-byte nonces .Em cannot because they are too small and the same nonce may be selected twice by accident. See .Xr intro 3monocypher for advice about generating random numbers (use the operating system's random number generator). .It Fa plain_text The message to encrypt. It is allowed to be .Dv NULL , in which case it will be interpreted as an all-zero input. .Fa cipher_text will then contain the raw ChaCha20 stream. .It Fa cipher_text The encrypted message. .It Fa text_size Length of both .Fa plain_text and .Fa cipher_text , in bytes. .It Fa ctr The number of 64-byte blocks we skip from the beginning of the stream. 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. Should be zero by default. When using this, be careful not to accidentally reuse parts of the random stream as that would destroy confidentiality. The return value can help here. .El .Pp The .Fa key and .Fa nonce buffers may overlap. .Fa plain_text and .Fa cipher_text must either be the same buffer (for in-place encryption) or non-overlapping. .Pp .Fn crypto_chacha20_djb , .Fn crypto_chacha20_ietf , and .Fn crypto_chacha20_x perform a ChaCha20 operation. Their main difference is the size of their nonce and counter. .Fn crypto_chacha20_ietf in particular implements RFC 8439, and is provided strictly for compatibility with existing systems or standards compliance. .Pp .Fn crypto_chacha20_x Is the only function that uses a nonce long enough to be random. This makes it easier to use securely, and the performance hit of the extended nonce is often negligible in practice. Use it instead of .Fn crypto_chacha20_djb and .Fn crypto_chacha20_ietf if possible. .Pp The .Fn crypto_chacha20_djb , .Fn crypto_chacha20_ietf , and .Fn crypto_chacha20_x encrypt .Fa plain_text by XORing it with a pseudo-random stream of numbers, seeded by the provided .Fa key and .Fa nonce . .Pp Since XOR is its own inverse, decryption is the same operation as encryption. To decrypt the cipher text, .Dq 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 .Xr crypto_wipe 3monocypher to wipe them. .Pp The .Fa plain_text pointer is allowed to be .Dv NULL , in which case it will be interpreted as an all-zero input. This is useful as a user space random number generator. While .Sy 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 .Em can be used to generate large amounts of random-looking data quickly \(en for example to generate padding. .Sh RETURN VALUES .Fn crypto_chacha20_djb , .Fn crypto_chacha20_ietf , and .Fn crypto_chacha20_x return the next .Fa ctr to use with the same key and nonce values; this is the previous .Fa ctr , plus .Fa text_size divided by 64 (rounded up). .Sh EXAMPLES The following examples assume the existence of .Fn arc4random_buf , which fills the given buffer with cryptographically secure random bytes. If .Fn arc4random_buf does not exist on your system, see .Xr intro 3monocypher for advice about how to generate cryptographically secure random bytes. .Pp Simple encryption: .Bd -literal -offset indent 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_chacha20_x(cipher_text, plain_text, 500, key, nonce, 0); /* Wipe secrets if they are no longer needed */ crypto_wipe(key, 32); crypto_wipe(plain_text, 500); .Ed .Pp To decrypt the above: .Bd -literal -offset indent 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_chacha20_x(cipher_text, plain_text, 500, key, nonce, 0); /* 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); .Ed .Pp Incremental encryption (in blocks of 64 bytes): .Bd -literal -offset indent 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_chacha20_x(cipher_text+i, plain_text+i, 64, key, nonce, ctr); } /* Process data that didn't fit into 64-byte pieces */ crypto_chacha20_x(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); .Ed .Pp Encryption by jumping around (do not do this, this is only meant to show how the counter works): .Bd -literal -offset indent 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_chacha20_x(cipher_text + (3 * 64), plain_text + (3 * 64), 500 - (3 * 64), key, nonce, 3); /* ...then encrypt the first part */ crypto_chacha20_x(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); .Ed .Sh HCHACHA20 .Fn crypto_chacha20_h provides a not-so-cryptographic hash. .Sy This is not a general-purpose cryptographic hash function . It may be used for some specific purposes such as X25519 key derivation or XChaCha20 initialisation. If in doubt, do not use directly. Use .Xr crypto_blake2b 3monocypher instead. .Pp The arguments are: .Bl -tag -width Ds .It Fa key A sufficiently random key, such as the output of .Xr crypto_x25519 3monocypher . .It Fa in The space reserved for the ChaCha20 nonce and counter. It does not have to be random. .It Fa out A cryptographically secure random number .Em if there is enough entropy in .Fa key . X25519 shared secrets have enough entropy. .El .Pp For instance: .Bd -literal -offset indent uint8_t key[32]; /* Must have enough entropy */ uint8_t in [16]; /* Does not have to be random */ uint8_t out[32]; /* Will be random iff the above holds */ arc4random_buf(key, 32); crypto_chacha20_h(out, key, in); /* Wipe secrets if they are no longer needed */ crypto_wipe(key, 32); crypto_wipe(in , 16); .Ed .Sh SEE ALSO .Xr crypto_aead_lock 3monocypher , .Xr crypto_wipe 3monocypher , .Xr intro 3monocypher .Sh STANDARDS These functions implement ChaCha20, XChaCha20, and HChaCha20. ChaCha20 is described in: .Rs .%A Daniel J. Bernstein .%J SASC 2008 \(en The State of the Art of Stream Ciphers .%P pp. 273\(en278 .%T ChaCha, a variant of Salsa20 .Re The nonce and counter sizes were modified in RFC 8439. XChaCha20 derives from ChaCha20 the same way XSalsa20 derives from Salsa20 and benefits from the same security reduction (proven secure as long as ChaCha20 itself is secure). .Sh HISTORY .Fn crypto_chacha20 , .Fn crypto_chacha20_ctr , .Fn crypto_ietf_chacha20 , .Fn crypto_ietf_chacha20_ctr , .Fn crypto_xchacha20 , and .Fn crypto_xchacha20_ctr were added in Monocypher 3.0.0. They replace .Fn crypto_chacha20_encrypt , .Fn crypto_chacha20_init , .Fn crypto_chacha20_stream , .Fn crypto_chacha20_x_init , and .Fn crypto_chacha20_set_ctr that were deprecated in Monocypher 3.0.0. In Monocypher 4.0.0, only the ctr variants have been kept, and were renamed .Fn crypto_chacha20_djb , .Fn crypto_chacha20_ietf , and .Fn crypto_chacha20_x respectively. .Pp .Fn crypto_chacha20_h function first appeared in Monocypher 0.1 as .Fn crypto_chacha20_H . It was renamed to .Fn crypto_hchacha20 in Monocypher 3.0.0, then .Fn crypto_chacha20_h in Monocypher 4.0.0. .Sh CAVEATS Monocypher does not perform any input validation. Any deviation from the specified input and output length ranges results in .Sy undefined behaviour . Make sure your inputs are correct. .Sh SECURITY CONSIDERATIONS .Ss Encrypted does not mean secure ChaCha20 only protects against eavesdropping, not forgeries. Most applications need protection against forgeries to be properly secure. To ensure the integrity of a message, use BLAKE2b in keyed mode or authenticated encryption; see .Xr crypto_blake2b 3monocypher and .Xr crypto_aead_lock 3monocypher . .Ss Nonce reuse Repeating a nonce with the same key exposes the XOR of two or more plaintext messages, effectively destroying confidentiality. .Pp For the same reason, .Sy do not select small nonces at random . The .Fn crypto_chacha20_djb 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. .Ss Secure random number generation Do not use these functions as a cryptographic random number generator. Always use the operating system's random number generator for cryptographic purposes; see .Xr intro 3monocypher . .Ss Protection against side channels Secrets should not dwell in memory longer than needed. Use .Xr crypto_wipe 3monocypher to erase secrets you no longer need. For ChaCha20, this means the key and in some cases the plaintext itself.