use super::{
noxtls_poly1305_key_gen_prepared, noxtls_poly1305_mac_aead, noxtls_poly1305_tags_equal,
ChaCha20,
};
use crate::internal_alloc::Vec;
use noxtls_core::{Error, Result};
pub fn noxtls_chacha20_poly1305_encrypt(
key: &[u8; 32],
nonce: &[u8; 12],
aad: &[u8],
plaintext: &[u8],
) -> Result<(Vec<u8>, [u8; 16])> {
const MAX_PLAINTEXT: usize = if usize::BITS < 64 {
usize::MAX
} else {
(1_usize << 32).saturating_mul(64).saturating_sub(64)
};
if plaintext.len() > MAX_PLAINTEXT {
return Err(Error::InvalidLength(
"chacha20-poly1305 plaintext exceeds RFC 8439 counter range",
));
}
let prepared = ChaCha20::noxtls_prepare_key_words(key);
let otk = noxtls_poly1305_key_gen_prepared(&prepared, nonce);
let mut cipher = ChaCha20::noxtls_from_prepared(&prepared, nonce, 1);
let mut ciphertext = vec![0_u8; plaintext.len()];
cipher.apply_keystream(plaintext, &mut ciphertext)?;
let tag = noxtls_poly1305_mac_aead(&otk, aad, &ciphertext);
Ok((ciphertext, tag))
}
pub fn noxtls_chacha20_poly1305_decrypt(
key: &[u8; 32],
nonce: &[u8; 12],
aad: &[u8],
ciphertext: &[u8],
tag: &[u8; 16],
) -> Result<Vec<u8>> {
const MAX_CIPHERTEXT: usize = if usize::BITS < 64 {
usize::MAX
} else {
(1_usize << 32).saturating_mul(64).saturating_sub(64)
};
if ciphertext.len() > MAX_CIPHERTEXT {
return Err(Error::InvalidLength(
"chacha20-poly1305 ciphertext exceeds RFC 8439 counter range",
));
}
let prepared = ChaCha20::noxtls_prepare_key_words(key);
let otk = noxtls_poly1305_key_gen_prepared(&prepared, nonce);
let expected = noxtls_poly1305_mac_aead(&otk, aad, ciphertext);
if !noxtls_poly1305_tags_equal(tag, &expected) {
return Err(Error::CryptoFailure(
"chacha20-poly1305 authentication failed",
));
}
let mut cipher = ChaCha20::noxtls_from_prepared(&prepared, nonce, 1);
let mut plaintext = vec![0_u8; ciphertext.len()];
cipher.apply_keystream(ciphertext, &mut plaintext)?;
Ok(plaintext)
}