use aes_siv::{aead::generic_array::GenericArray, siv::Aes256Siv, KeyInit};
use std::{cell::RefCell, rc::Rc};
use tink_core::{utils::wrap_err, TinkError};
const AES_BLOCK_SIZE: usize = 16;
#[derive(Clone)]
pub struct AesSiv {
cipher: Rc<RefCell<Aes256Siv>>,
}
pub const AES_SIV_KEY_SIZE: usize = 64;
impl AesSiv {
pub fn new(key: &[u8]) -> Result<AesSiv, TinkError> {
if key.len() != AES_SIV_KEY_SIZE {
return Err(format!("AesSiv::new: invalid key size {}", key.len()).into());
}
Ok(AesSiv {
cipher: Rc::new(RefCell::new(Aes256Siv::new(GenericArray::from_slice(key)))),
})
}
}
impl tink_core::DeterministicAead for AesSiv {
fn encrypt_deterministically(
&self,
plaintext: &[u8],
additional_data: &[u8],
) -> Result<Vec<u8>, TinkError> {
if plaintext.len() > (isize::MAX as usize) - AES_BLOCK_SIZE {
return Err("AesSiv: plaintext too long".into());
}
self.cipher
.borrow_mut()
.encrypt([additional_data], plaintext)
.map_err(|e| wrap_err("AesSiv: encrypt failed", e))
}
fn decrypt_deterministically(
&self,
ciphertext: &[u8],
additional_data: &[u8],
) -> Result<Vec<u8>, TinkError> {
if ciphertext.len() < aes_siv::siv::IV_SIZE {
return Err("AesSiv: ciphertext is too short".into());
}
self.cipher
.borrow_mut()
.decrypt([additional_data], ciphertext)
.map_err(|e| wrap_err("AesSiv: decrypt failed", e))
}
}