use tls_codec::SecretVLBytes;
use super::*;
pub(crate) const NONCE_BYTES: usize = 12;
#[derive(Serialize, Deserialize)]
#[cfg_attr(any(feature = "test-utils", test), derive(Clone, PartialEq, Eq))]
#[cfg_attr(feature = "crypto-debug", derive(Debug))]
pub struct AeadKey {
aead_mode: AeadType,
value: SecretVLBytes,
}
#[cfg(not(feature = "crypto-debug"))]
impl core::fmt::Debug for AeadKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AeadKey")
.field("aead_mode", &self.aead_mode)
.field("value", &"***")
.finish()
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "crypto-debug", derive(Debug))]
pub(crate) struct AeadNonce([u8; NONCE_BYTES]);
#[cfg(not(feature = "crypto-debug"))]
impl core::fmt::Debug for AeadNonce {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("AeadNonce").field(&"***").finish()
}
}
impl AeadKey {
pub(crate) fn from_secret(secret: Secret, ciphersuite: Ciphersuite) -> Self {
log::trace!("AeadKey::from_secret with {ciphersuite}");
AeadKey {
aead_mode: ciphersuite.aead_algorithm(),
value: secret.value,
}
}
#[cfg(test)]
pub(crate) fn random(ciphersuite: Ciphersuite, rng: &impl OpenMlsRand) -> Self {
AeadKey {
aead_mode: ciphersuite.aead_algorithm(),
value: aead_key_gen(ciphersuite.aead_algorithm(), rng),
}
}
#[cfg(any(feature = "test-utils", test))]
pub(crate) fn as_slice(&self) -> &[u8] {
self.value.as_slice()
}
pub(crate) fn aead_seal(
&self,
crypto: &impl OpenMlsCrypto,
msg: &[u8],
aad: &[u8],
nonce: &AeadNonce,
) -> Result<Vec<u8>, CryptoError> {
crypto
.aead_encrypt(self.aead_mode, self.value.as_slice(), msg, &nonce.0, aad)
.map_err(|_| CryptoError::CryptoLibraryError)
}
pub(crate) fn aead_open(
&self,
crypto: &impl OpenMlsCrypto,
ciphertext: &[u8],
aad: &[u8],
nonce: &AeadNonce,
) -> Result<Vec<u8>, CryptoError> {
crypto
.aead_decrypt(
self.aead_mode,
self.value.as_slice(),
ciphertext,
&nonce.0,
aad,
)
.map_err(|_| CryptoError::AeadDecryptionError)
}
}
impl AeadNonce {
pub(crate) fn from_secret(secret: Secret) -> Self {
let mut nonce = [0u8; NONCE_BYTES];
nonce.clone_from_slice(secret.value.as_slice());
Self(nonce)
}
#[cfg(test)]
pub(crate) fn random(rng: &impl OpenMlsRand) -> Self {
Self(rng.random_array().expect("Not enough entropy."))
}
#[cfg(any(feature = "test-utils", test))]
pub(crate) fn as_slice(&self) -> &[u8] {
&self.0
}
pub(crate) fn xor_with_reuse_guard(mut self, reuse_guard: &ReuseGuard) -> Self {
log_crypto!(
trace,
" XOR re-use guard {:x?}^{:x?}",
self.0,
reuse_guard.value
);
for i in 0..REUSE_GUARD_BYTES {
self.0[i] ^= reuse_guard.value[i]
}
log_crypto!(trace, " = {:x?}", self.0);
self
}
}
#[cfg(test)]
pub(crate) fn aead_key_gen(
alg: openmls_traits::types::AeadType,
rng: &impl OpenMlsRand,
) -> SecretVLBytes {
match alg {
openmls_traits::types::AeadType::Aes128Gcm => rng
.random_vec(16)
.expect("An unexpected error occurred.")
.into(),
openmls_traits::types::AeadType::Aes256Gcm
| openmls_traits::types::AeadType::ChaCha20Poly1305 => rng
.random_vec(32)
.expect("An unexpected error occurred.")
.into(),
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[openmls_test::openmls_test]
fn test_xor() {
let provider = &Provider::default();
let reuse_guard: ReuseGuard =
ReuseGuard::try_from_random(provider.rand()).expect("An unexpected error occurred.");
let original_nonce = AeadNonce::random(provider.rand());
let xored_once = original_nonce.clone().xor_with_reuse_guard(&reuse_guard);
assert_ne!(
original_nonce, xored_once,
"xoring with reuse_guard did not change the nonce"
);
let xored_twice = xored_once.xor_with_reuse_guard(&reuse_guard);
assert_eq!(
original_nonce, xored_twice,
"xoring twice changed the original value"
);
}
}