#![cfg(feature = "encryption")]
use super::aad::{AAD_LEN, SuiteId};
use super::error::DecryptError;
pub const TAG_LEN: usize = 16;
pub fn encrypt_in_place(
suite: SuiteId,
key: &[u8; 32],
nonce: &[u8],
aad: &[u8; AAD_LEN],
plaintext: &mut [u8],
) -> crate::Result<[u8; TAG_LEN]> {
use aes_gcm::aead::{AeadInOut, KeyInit, Nonce};
match suite {
SuiteId::Aes256Gcm => {
let cipher = aes_gcm::Aes256Gcm::new(key.into());
let nonce = Nonce::<aes_gcm::Aes256Gcm>::try_from(nonce)
.map_err(|_| crate::Error::Encrypt("AES-256-GCM nonce length mismatch"))?;
let tag = cipher
.encrypt_inout_detached(&nonce, aad, plaintext.into())
.map_err(|_| crate::Error::Encrypt("AES-256-GCM encryption failed"))?;
let mut out = [0u8; TAG_LEN];
out.copy_from_slice(&tag);
Ok(out)
}
SuiteId::ChaCha20Poly1305 => {
let cipher = chacha20poly1305::ChaCha20Poly1305::new(key.into());
let nonce = Nonce::<chacha20poly1305::ChaCha20Poly1305>::try_from(nonce)
.map_err(|_| crate::Error::Encrypt("ChaCha20-Poly1305 nonce length mismatch"))?;
let tag = cipher
.encrypt_inout_detached(&nonce, aad, plaintext.into())
.map_err(|_| crate::Error::Encrypt("ChaCha20-Poly1305 encryption failed"))?;
let mut out = [0u8; TAG_LEN];
out.copy_from_slice(&tag);
Ok(out)
}
}
}
pub fn decrypt_in_place(
suite: SuiteId,
key: &[u8; 32],
nonce: &[u8],
aad: &[u8; AAD_LEN],
tag: &[u8; TAG_LEN],
ciphertext: &mut [u8],
) -> Result<(), DecryptError> {
use aes_gcm::aead::{AeadInOut, KeyInit, Nonce, Tag};
match suite {
SuiteId::Aes256Gcm => {
let cipher = aes_gcm::Aes256Gcm::new(key.into());
let nonce = Nonce::<aes_gcm::Aes256Gcm>::try_from(nonce)
.map_err(|_| DecryptError::MalformedBodyFrame("nonce length != suite nonce_len"))?;
let aead_tag = Tag::<aes_gcm::Aes256Gcm>::try_from(&tag[..])
.map_err(|_| DecryptError::MalformedBodyFrame("tag length != 16"))?;
cipher
.decrypt_inout_detached(&nonce, aad, ciphertext.into(), &aead_tag)
.map_err(|_| DecryptError::AeadVerificationFailed)
}
SuiteId::ChaCha20Poly1305 => {
let cipher = chacha20poly1305::ChaCha20Poly1305::new(key.into());
let nonce = Nonce::<chacha20poly1305::ChaCha20Poly1305>::try_from(nonce)
.map_err(|_| DecryptError::MalformedBodyFrame("nonce length != suite nonce_len"))?;
let aead_tag = Tag::<chacha20poly1305::ChaCha20Poly1305>::try_from(&tag[..])
.map_err(|_| DecryptError::MalformedBodyFrame("tag length != 16"))?;
cipher
.decrypt_inout_detached(&nonce, aad, ciphertext.into(), &aead_tag)
.map_err(|_| DecryptError::AeadVerificationFailed)
}
}
}
#[cfg(test)]
#[expect(
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
reason = "test code"
)]
mod tests;