use crate::{Cipher, Error, Result};
use cipher::KeyIvInit;
#[cfg(feature = "aes-ctr")]
use crate::{encryptor::ctr_encrypt as ctr_decrypt, Ctr128BE};
#[cfg(feature = "tdes")]
use des::TdesEde3;
#[cfg(any(feature = "aes-cbc", feature = "aes-ctr"))]
use aes::{Aes128, Aes192, Aes256};
#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
use cipher::{Block, BlockCipher, BlockCipherDecrypt, BlockModeDecrypt};
pub struct Decryptor {
inner: Inner,
}
#[derive(Clone)]
enum Inner {
#[cfg(feature = "aes-cbc")]
Aes128Cbc(cbc::Decryptor<Aes128>),
#[cfg(feature = "aes-cbc")]
Aes192Cbc(cbc::Decryptor<Aes192>),
#[cfg(feature = "aes-cbc")]
Aes256Cbc(cbc::Decryptor<Aes256>),
#[cfg(feature = "aes-ctr")]
Aes128Ctr(Ctr128BE<Aes128>),
#[cfg(feature = "aes-ctr")]
Aes192Ctr(Ctr128BE<Aes192>),
#[cfg(feature = "aes-ctr")]
Aes256Ctr(Ctr128BE<Aes256>),
#[cfg(feature = "tdes")]
TDesCbc(cbc::Decryptor<TdesEde3>),
}
impl Inner {
fn decrypt(&mut self, buffer: &mut [u8]) -> Result<()> {
#[cfg(any(feature = "aes-cbc", feature = "aes-ctr", feature = "tdes"))]
match self {
#[cfg(feature = "aes-cbc")]
Self::Aes128Cbc(cipher) => cbc_decrypt(cipher, buffer),
#[cfg(feature = "aes-cbc")]
Self::Aes192Cbc(cipher) => cbc_decrypt(cipher, buffer),
#[cfg(feature = "aes-cbc")]
Self::Aes256Cbc(cipher) => cbc_decrypt(cipher, buffer),
#[cfg(feature = "aes-ctr")]
Self::Aes128Ctr(cipher) => ctr_decrypt(cipher, buffer),
#[cfg(feature = "aes-ctr")]
Self::Aes192Ctr(cipher) => ctr_decrypt(cipher, buffer),
#[cfg(feature = "aes-ctr")]
Self::Aes256Ctr(cipher) => ctr_decrypt(cipher, buffer),
#[cfg(feature = "tdes")]
Self::TDesCbc(cipher) => cbc_decrypt(cipher, buffer),
}
.map_err(|_| Error::Length)?;
Ok(())
}
}
impl Decryptor {
pub fn new(cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self> {
cipher.check_key_and_iv(key, iv)?;
let inner = match cipher {
#[cfg(feature = "aes-cbc")]
Cipher::Aes128Cbc => cbc::Decryptor::new_from_slices(key, iv).map(Inner::Aes128Cbc),
#[cfg(feature = "aes-cbc")]
Cipher::Aes192Cbc => cbc::Decryptor::new_from_slices(key, iv).map(Inner::Aes192Cbc),
#[cfg(feature = "aes-cbc")]
Cipher::Aes256Cbc => cbc::Decryptor::new_from_slices(key, iv).map(Inner::Aes256Cbc),
#[cfg(feature = "aes-ctr")]
Cipher::Aes128Ctr => Ctr128BE::new_from_slices(key, iv).map(Inner::Aes128Ctr),
#[cfg(feature = "aes-ctr")]
Cipher::Aes192Ctr => Ctr128BE::new_from_slices(key, iv).map(Inner::Aes192Ctr),
#[cfg(feature = "aes-ctr")]
Cipher::Aes256Ctr => Ctr128BE::new_from_slices(key, iv).map(Inner::Aes256Ctr),
#[cfg(feature = "tdes")]
Cipher::TDesCbc => cbc::Decryptor::new_from_slices(key, iv).map(Inner::TDesCbc),
_ => return Err(cipher.unsupported()),
}
.map_err(|_| Error::Length)?;
Ok(Self { inner })
}
pub fn cipher(&self) -> Cipher {
match &self.inner {
#[cfg(feature = "aes-cbc")]
Inner::Aes128Cbc(_) => Cipher::Aes128Cbc,
#[cfg(feature = "aes-cbc")]
Inner::Aes192Cbc(_) => Cipher::Aes192Cbc,
#[cfg(feature = "aes-cbc")]
Inner::Aes256Cbc(_) => Cipher::Aes256Cbc,
#[cfg(feature = "aes-ctr")]
Inner::Aes128Ctr(_) => Cipher::Aes128Ctr,
#[cfg(feature = "aes-ctr")]
Inner::Aes192Ctr(_) => Cipher::Aes192Ctr,
#[cfg(feature = "aes-ctr")]
Inner::Aes256Ctr(_) => Cipher::Aes256Ctr,
#[cfg(feature = "tdes")]
Inner::TDesCbc(_) => Cipher::TDesCbc,
}
}
pub fn decrypt(&mut self, buffer: &mut [u8]) -> Result<()> {
self.inner.decrypt(buffer)
}
pub fn peek_decrypt(&self, buffer: &mut [u8]) -> Result<()> {
let mut inner = self.inner.clone();
inner.decrypt(buffer)
}
}
#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
fn cbc_decrypt<C>(decryptor: &mut cbc::Decryptor<C>, buffer: &mut [u8]) -> Result<()>
where
C: BlockCipher + BlockCipherDecrypt,
{
let (blocks, remaining) = Block::<C>::slice_as_chunks_mut(buffer);
if !remaining.is_empty() {
return Err(Error::Length);
}
decryptor.decrypt_blocks(blocks);
Ok(())
}