use ::cipher::StreamCipher;
use aead::Error;
use poly1305::Poly1305;
use super::Tag;
pub(crate) struct Cipher<C>
where
C: StreamCipher,
{
cipher: C,
mac: Poly1305,
}
impl<C> Cipher<C>
where
C: StreamCipher,
{
pub(crate) fn new(cipher: C, mac: Poly1305) -> Self {
Self { cipher, mac }
}
pub(crate) fn encrypt_in_place_detached(
mut self,
associated_data: &[u8],
buffer: &mut [u8],
) -> Result<Tag, Error> {
if !associated_data.is_empty() {
return Err(Error);
}
self.cipher.apply_keystream(buffer);
Ok(self.mac.compute_unpadded(buffer).into_bytes())
}
pub(crate) fn decrypt_in_place_detached(
mut self,
associated_data: &[u8],
buffer: &mut [u8],
tag: &Tag,
) -> Result<(), Error> {
if !associated_data.is_empty() {
return Err(Error);
}
use subtle::ConstantTimeEq;
let expected_tag = self.mac.compute_unpadded(buffer).into_bytes();
if expected_tag.ct_eq(&tag).unwrap_u8() == 1 {
self.cipher.apply_keystream(buffer);
Ok(())
} else {
Err(Error)
}
}
}