silk.crypto.chacha20_poly1305.
Encrypt and authenticate data with ChaCha20-Poly1305 (RFC 8439).
When to use#
Use ChaCha20Poly1305.seal to encrypt a message so that only holders of the key can read it
and any change is detected. Use ChaCha20Poly1305.open to check and decrypt it. It is fast
without AES hardware, and it is a cipher suite of TLS 1.3 and WireGuard.
Details#
The key is 32 bytes, the nonce is 12 bytes, and the tag is 16 bytes. The tag is separate from
the ciphertext ("detached"), so store or send both. The associated data (aad) is authenticated
but not encrypted. The ciphertext has the same length as the plaintext. Nothing allocates.
Errors#
The functions return an AeadError. All checks come before the first write, and on any error
the output buffers do not change. ChaCha20Poly1305.open writes no plaintext unless the tag
is correct.
Gotchas#
The same key and nonce must never encrypt two messages. If they do, an attacker can recover the
XOR of the two plaintexts and forge tags. Use a counter, or 12 random bytes from silk.system.random
for a small number of messages per key.
Authentication does not stop replay. The source code avoids branches on secret data, but the module cannot promise constant time on every compiler and target, or that secrets are erased.
Examples#
Encrypt, decrypt, and detect a change#
import silk.crypto.chacha20_poly1305 { AeadError, ChaCha20Poly1305 }
import silk.core.result { Result }
pub fn main() -> i32 {
let key: [u8; 32] = [42; 32]
let nonce: [u8; 12] = [0; 12]
let mut ciphertext: [u8; 5] = [0; 5]
let mut tag: [u8; 16] = [0; 16]
match ChaCha20Poly1305.seal(&key, &nonce, b"v1", b"hello", &mut ciphertext, &mut tag) {
Result<(), AeadError>.Success { value: _ } => {}
Result<(), AeadError>.Failure { error: _ } => {
return 1
}
}
let mut plaintext: [u8; 5] = [0; 5]
match ChaCha20Poly1305.open(&key, &nonce, b"v1", &ciphertext, &tag, &mut plaintext) {
Result<(), AeadError>.Success { value: _ } => {}
Result<(), AeadError>.Failure { error: _ } => {
return 1
}
}
if plaintext[0] != 104 || plaintext[4] != 111 {
return 1
}
// Other associated data gives a different tag, so open fails.
return match ChaCha20Poly1305.open(&key, &nonce, b"v2", &ciphertext, &tag, &mut plaintext) {
Result<(), AeadError>.Failure { error: AeadError.AuthenticationFailed } => 0
_ => 1
}
}Import as ChaCha20Poly1305 with import silk.crypto.chacha20_poly1305 { ChaCha20Poly1305 }.
Public declarations: 2.
AeadError#
pub enum AeadErrorThe reason that ChaCha20Poly1305.seal or ChaCha20Poly1305.open rejected a call. The
checks run in the order of the variants, and the first failure is returned.
InvalidKey#
InvalidKeyThe key is not 32 bytes.
InvalidNonce#
InvalidNonceThe nonce is not 12 bytes.
InvalidTag#
InvalidTagThe tag, or the tag output, is not 16 bytes.
OutputTooSmall#
OutputTooSmallThe output is shorter than the input message.
LimitExceeded#
LimitExceededThe message is longer than 274877906880 bytes (2^32 blocks of 64 bytes).
AuthenticationFailed#
AuthenticationFailedThe tag is not correct for the key, nonce, associated data, and ciphertext.
Implementation Debug for AeadError#
impl Debug for AeadErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InvalidKey.
ChaCha20Poly1305#
pub struct ChaCha20Poly1305Functions that encrypt and authenticate with ChaCha20-Poly1305 (RFC 8439).
When to use#
Use ChaCha20Poly1305.seal to encrypt a message so that only holders of the key can read it
and any change is detected. Use ChaCha20Poly1305.open to check and decrypt it. It is fast
without AES hardware, and it is a cipher suite of TLS 1.3 and WireGuard.
Details#
The key is 32 bytes, the nonce is 12 bytes, and the tag is 16 bytes. The tag is separate from the ciphertext, so store or send both. The ciphertext has the same length as the plaintext. Nothing allocates. All checks come before the first write, and on any error the output buffers do not change.
Gotchas#
The same key and nonce must never encrypt two messages. If they do, an attacker can recover the XOR of the two plaintexts and forge tags. Authentication does not stop replay. The source code avoids branches on secret data, but it cannot promise constant time on every compiler and target, or that secrets are erased.
Implementation ChaCha20Poly1305#
impl ChaCha20Poly1305Associated function seal#
pub fn seal(key: &[u8], nonce: &[u8], aad: &[u8], plaintext: &[u8], ciphertext: &mut [u8], tag: &mut [u8]) -> Result<(), AeadError>Encrypts plaintext into ciphertext and writes the 16-byte authentication tag to tag.
The key is 32 bytes and the nonce is 12 bytes. aad is authenticated but not encrypted. The
ciphertext has the same length as plaintext. ciphertext can be longer than plaintext.
The bytes after the written prefix do not change. Nothing allocates.
Errors#
All checks come before the first write. On an error, ciphertext and tag do not change.
The first failure in this order is returned:
InvalidKeyifkeyis not 32 bytes.InvalidNonceifnonceis not 12 bytes.InvalidTagiftagis not 16 bytes.OutputTooSmallifciphertextis shorter thanplaintext.LimitExceededifplaintextis longer than 274877906880 bytes (2^32 blocks of 64 bytes).
Gotchas#
Use a new nonce for each message under the same key. The function does not make one. If the
same key and nonce encrypt two messages, an attacker can recover the XOR of the two plaintexts
and forge tags. Use a counter, or 12 random bytes from silk.system.random for a small number of
messages per key.
Associated function open#
pub fn open(key: &[u8], nonce: &[u8], aad: &[u8], ciphertext: &[u8], tag: &[u8], plaintext: &mut [u8]) -> Result<(), AeadError>Checks tag, and if it is correct, decrypts ciphertext into plaintext.
aad must be the same bytes that were given to ChaCha20Poly1305.seal. The function checks
all 16 tag bytes before it writes plaintext. The bytes after the written prefix do not
change.
The key is 32 bytes, the nonce is 12 bytes, and the tag is 16 bytes. Nothing allocates.
Errors#
All checks come before the first write. On an error, plaintext does not change.
InvalidKeyifkeyis not 32 bytes.InvalidNonceifnonceis not 12 bytes.InvalidTagiftagis not 16 bytes.OutputTooSmallifplaintextis shorter thanciphertext.LimitExceededifciphertextis longer than 274877906880 bytes.AuthenticationFailedif the tag is not correct for the key, nonce,aad, and ciphertext.
Gotchas#
Authentication does not stop replay: an attacker can send an old valid message again.
Category: Cryptography.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.