std/cipher/aead
std/cipher/src/aead.trb
AEAD_CHACHA20_POLY1305 of RFC 8439 section 2.8: ChaCha20Poly1305 seals a message under a key and a nonce, with
associated data that is authenticated and not hidden, and opens it again.
type ChaCha20Poly1305
type ChaCha20Poly1305 with Show, Encode, TryFrom<Bytes, CipherError>
A ChaCha20-Poly1305 key: exactly 32 bytes of the system's source of randomness. It seals with
ChaCha20Poly1305.seal and opens with ChaCha20Poly1305.open.
Its Show and its Encode write no byte of the key, so a key that ends up in a log line or in an encoded
configuration does not leak.
Examples
const bytes: Bytes = Buffer.from List.filled(32, 3)
const key = ChaCha20Poly1305.tryFrom(bytes).expect("32 bytes")
const nonce: Bytes = Buffer.from List.filled(12, 9)
const sealed = key.seal(nonce, "hello".bytes(), []).expect("a 12-byte nonce")
const opened = key.open(nonce, sealed, []).expect("sealed just now")
print(opened == "hello".bytes())
// prints true
Pitfalls
- A nonce must never repeat under one key. Two messages sealed under the same key and nonce give away the XOR of their plaintexts, and let a forger make tags. Random 96-bit nonces are safe for up to about 2^32 messages per key; beyond that, count the messages and use the count, or change the key.
==andhash()of two keys are generated over the key and are not constant time: do not compare keys with them.- A message is at most 274 877 906 880 bytes (RFC 8439 section 2.8), a limit no list reaches.
- Where the key and the nonces come from is the caller's:
std/ciphermakes no randomness (docs/design/RANDOM.md). - What is constant time: the comparison of the tag in
ChaCha20Poly1305.open. The arithmetic of ChaCha20 and Poly1305 is plainIntarithmetic of the language, with no data-dependent branch or index in its source, and promises nothing more: a compiler or a CPU may introduce a timing effect.
fn tryFrom
static fn tryFrom(key: Bytes): Result<Self, CipherError>
The key of key, which is 32 bytes.
Errors
CipherError.WrongLengthfor a key that is not 32 bytes.
fn seal
fn seal(nonce: Bytes, plaintext: Bytes, associated: Bytes): Result<Bytes, CipherError>
plaintext sealed under this key and nonce (12 bytes): the ciphertext, which is as long as the plaintext, followed
by the 16-byte tag. The tag also covers associated, which is not part of the answer and is not hidden: the one
who opens has to give the same bytes (RFC 8439 section 2.8).
Errors
CipherError.WrongLengthfor a nonce that is not 12 bytes.
fn open
fn open(nonce: Bytes, sealed: Bytes, associated: Bytes): Result<Bytes, CipherError>
The plaintext of sealed, the ciphertext followed by its tag, under this key, nonce and associated. The tag is
computed from the ciphertext and compared first, in constant time; the ciphertext is decrypted only after it
matched, so no byte of a forgery is ever released.
Errors
CipherError.WrongLengthfor a nonce that is not 12 bytes.CipherError.Forgedfor sealed bytes of fewer than 16 bytes, and for every tag that does not match, whichever of the key, the nonce, the associated data, the ciphertext or the tag is not the one that sealed it.
fn show
fn show(): String
ChaCha20Poly1305(key hidden): no byte of the key is shown.
fn encode
fn encode<Target: Encoder>(var target: Target)
What ChaCha20Poly1305.show writes, as a string: an encoded configuration never carries the key.