use ring::{aead::*, error::Unspecified};
use crate::{
create_security_error_and_log,
security::{SecurityError, SecurityResult},
};
use super::{
builtin_key::*,
types::{BuiltinInitializationVector, BuiltinMAC, MAC_LENGTH},
};
struct TrivialNonceSequence {
iv: BuiltinInitializationVector,
used: bool, }
impl TrivialNonceSequence {
fn new(iv: BuiltinInitializationVector) -> Self {
TrivialNonceSequence { iv, used: false }
}
}
impl NonceSequence for TrivialNonceSequence {
fn advance(&mut self) -> Result<Nonce, Unspecified> {
if self.used {
Err(Unspecified) } else {
self.used = true;
Ok(Nonce::assume_unique_for_key(self.iv.into()))
}
}
}
pub(super) fn keygen(key_length: KeyLength) -> BuiltinKey {
BuiltinKey::generate_random(key_length)
}
#[allow(non_snake_case)]
fn to_unbound_AES_GCM_key(key: &BuiltinKey) -> SecurityResult<UnboundKey> {
match key {
BuiltinKey::None => Err(create_security_error_and_log!(
"Attempted to call a cryptographic function with an empty key."
)),
BuiltinKey::AES128(key) => Ok(UnboundKey::new(&AES_128_GCM, key).unwrap()),
BuiltinKey::AES256(key) => Ok(UnboundKey::new(&AES_256_GCM, key).unwrap()),
}
}
fn to_builtin_mac(tag: &Tag) -> BuiltinMAC {
tag.as_ref().try_into().unwrap()
}
pub(super) fn compute_mac(
key: &BuiltinKey,
initialization_vector: BuiltinInitializationVector,
data: &[u8],
) -> SecurityResult<BuiltinMAC> {
let mut sealing_key = SealingKey::new(
to_unbound_AES_GCM_key(key)?,
TrivialNonceSequence::new(initialization_vector),
);
let tag = sealing_key.seal_in_place_separate_tag(Aad::from(data), &mut [])?;
Ok(to_builtin_mac(&tag))
}
pub(super) fn encrypt(
key: &BuiltinKey,
initialization_vector: BuiltinInitializationVector,
plaintext: &[u8],
) -> SecurityResult<(Vec<u8>, BuiltinMAC)> {
let mut in_out_data = Vec::from(plaintext);
let mut sealing_key = SealingKey::new(
to_unbound_AES_GCM_key(key)?,
TrivialNonceSequence::new(initialization_vector),
);
let tag = sealing_key.seal_in_place_separate_tag(Aad::empty(), &mut in_out_data)?;
Ok((in_out_data, to_builtin_mac(&tag)))
}
pub(super) fn validate_mac(
key: &BuiltinKey,
initialization_vector: BuiltinInitializationVector,
data: &[u8],
mac: BuiltinMAC,
) -> SecurityResult<()> {
let mut in_out = Vec::with_capacity(MAC_LENGTH);
in_out.extend_from_slice(&mac);
let mut opening_key = OpeningKey::new(
to_unbound_AES_GCM_key(key)?,
TrivialNonceSequence::new(initialization_vector),
);
let _plaintext = opening_key.open_in_place(Aad::from(data), &mut in_out)?;
Ok(())
}
pub(super) fn decrypt(
key: &BuiltinKey,
initialization_vector: BuiltinInitializationVector,
ciphertext: &[u8],
mac: BuiltinMAC,
) -> SecurityResult<Vec<u8>> {
let mut in_out = Vec::with_capacity(ciphertext.len() + MAC_LENGTH);
in_out.extend_from_slice(ciphertext.as_ref());
in_out.extend_from_slice(mac.as_ref());
let mut opening_key = OpeningKey::new(
to_unbound_AES_GCM_key(key)?,
TrivialNonceSequence::new(initialization_vector),
);
let plaintext = opening_key.open_in_place(Aad::empty(), &mut in_out)?;
let plain_len = plaintext.len();
in_out.truncate(plain_len);
Ok(in_out)
}