#[cfg(all(feature = "block-padding", feature = "alloc"))]
use alloc::{vec, vec::Vec};
use crypto_common::{Block, BlockSizeUser};
#[cfg(feature = "block-padding")]
use inout::{
block_padding::{Padding, UnpadError},
InOutBufReserved, PadError,
};
use inout::{InOut, InOutBuf, NotEqualError};
mod backends;
mod ctx;
use ctx::{BlockCtx, BlocksCtx};
pub use backends::{
BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherEncBackend, BlockCipherEncClosure,
BlockModeDecBackend, BlockModeDecClosure, BlockModeEncBackend, BlockModeEncClosure,
};
pub trait BlockCipherEncrypt: BlockSizeUser + Sized {
fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>);
#[inline]
fn encrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
self.encrypt_with_backend(BlockCtx { block });
}
#[inline]
fn encrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.encrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn encrypt_block(&self, block: &mut Block<Self>) {
let block = block.into();
self.encrypt_with_backend(BlockCtx { block });
}
#[inline]
fn encrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.encrypt_with_backend(BlockCtx { block });
}
#[inline]
fn encrypt_blocks(&self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.encrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn encrypt_blocks_b2b(
&self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
}
#[cfg(feature = "block-padding")]
#[inline]
fn encrypt_padded_inout<'out, P: Padding<Self::BlockSize>>(
&self,
data: InOutBufReserved<'_, 'out, u8>,
) -> Result<&'out [u8], PadError> {
let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
self.encrypt_blocks_inout(buf.get_blocks());
if let Some(block) = buf.get_tail_block() {
self.encrypt_block_inout(block);
}
Ok(buf.into_out())
}
#[cfg(feature = "block-padding")]
#[inline]
fn encrypt_padded<'a, P: Padding<Self::BlockSize>>(
&self,
buf: &'a mut [u8],
msg_len: usize,
) -> Result<&'a [u8], PadError> {
let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
self.encrypt_padded_inout::<P>(buf)
}
#[cfg(feature = "block-padding")]
#[inline]
fn encrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
&self,
msg: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], PadError> {
let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
self.encrypt_padded_inout::<P>(buf)
}
#[cfg(all(feature = "block-padding", feature = "alloc"))]
#[inline]
fn encrypt_padded_vec<P: Padding<Self::BlockSize>>(&self, msg: &[u8]) -> Vec<u8> {
use crypto_common::typenum::Unsigned;
let bs = Self::BlockSize::USIZE;
let mut out = vec![0; bs * (msg.len() / bs + 1)];
let len = self
.encrypt_padded_b2b::<P>(msg, &mut out)
.expect("enough space for encrypting is allocated")
.len();
out.truncate(len);
out
}
}
pub trait BlockCipherDecrypt: BlockSizeUser {
fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>);
#[inline]
fn decrypt_block_inout(&self, block: InOut<'_, '_, Block<Self>>) {
self.decrypt_with_backend(BlockCtx { block });
}
#[inline]
fn decrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.decrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn decrypt_block(&self, block: &mut Block<Self>) {
let block = block.into();
self.decrypt_with_backend(BlockCtx { block });
}
#[inline]
fn decrypt_block_b2b(&self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.decrypt_with_backend(BlockCtx { block });
}
#[inline]
fn decrypt_blocks(&self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.decrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn decrypt_blocks_b2b(
&self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
}
#[cfg(feature = "block-padding")]
#[inline]
fn decrypt_padded_inout<'out, P: Padding<Self::BlockSize>>(
&self,
data: InOutBuf<'_, 'out, u8>,
) -> Result<&'out [u8], UnpadError> {
let (mut blocks, tail) = data.into_chunks();
if !tail.is_empty() {
return Err(UnpadError);
}
self.decrypt_blocks_inout(blocks.reborrow());
P::unpad_blocks(blocks.into_out())
}
#[cfg(feature = "block-padding")]
#[inline]
fn decrypt_padded<'a, P: Padding<Self::BlockSize>>(
&self,
buf: &'a mut [u8],
) -> Result<&'a [u8], UnpadError> {
self.decrypt_padded_inout::<P>(buf.into())
}
#[cfg(feature = "block-padding")]
#[inline]
fn decrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
&self,
in_buf: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], UnpadError> {
if out_buf.len() < in_buf.len() {
return Err(UnpadError);
}
let n = in_buf.len();
let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?;
self.decrypt_padded_inout::<P>(buf)
}
#[cfg(all(feature = "block-padding", feature = "alloc"))]
#[inline]
fn decrypt_padded_vec<P: Padding<Self::BlockSize>>(
&self,
buf: &[u8],
) -> Result<Vec<u8>, UnpadError> {
let mut out = vec![0; buf.len()];
let len = self.decrypt_padded_b2b::<P>(buf, &mut out)?.len();
out.truncate(len);
Ok(out)
}
}
impl<Alg: BlockCipherEncrypt> BlockCipherEncrypt for &Alg {
fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
Alg::encrypt_with_backend(self, f);
}
}
impl<Alg: BlockCipherDecrypt> BlockCipherDecrypt for &Alg {
fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
Alg::decrypt_with_backend(self, f);
}
}
pub trait BlockModeEncrypt: BlockSizeUser + Sized {
fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure<BlockSize = Self::BlockSize>);
#[inline]
fn encrypt_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
self.encrypt_with_backend(BlockCtx { block });
}
#[inline]
fn encrypt_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.encrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn encrypt_block(&mut self, block: &mut Block<Self>) {
let block = block.into();
self.encrypt_with_backend(BlockCtx { block });
}
#[inline]
fn encrypt_block_b2b(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.encrypt_with_backend(BlockCtx { block });
}
#[inline]
fn encrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.encrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn encrypt_blocks_b2b(
&mut self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks }))
}
#[cfg(feature = "block-padding")]
#[inline]
fn encrypt_padded_inout<'out, P: Padding<Self::BlockSize>>(
mut self,
data: InOutBufReserved<'_, 'out, u8>,
) -> Result<&'out [u8], PadError> {
let mut buf = data.into_padded_blocks::<P, Self::BlockSize>()?;
self.encrypt_blocks_inout(buf.get_blocks());
if let Some(block) = buf.get_tail_block() {
self.encrypt_block_inout(block);
}
Ok(buf.into_out())
}
#[cfg(feature = "block-padding")]
#[inline]
fn encrypt_padded<P: Padding<Self::BlockSize>>(
self,
buf: &mut [u8],
msg_len: usize,
) -> Result<&[u8], PadError> {
let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?;
self.encrypt_padded_inout::<P>(buf)
}
#[cfg(feature = "block-padding")]
#[inline]
fn encrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
self,
msg: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], PadError> {
let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?;
self.encrypt_padded_inout::<P>(buf)
}
#[cfg(all(feature = "block-padding", feature = "alloc"))]
#[inline]
fn encrypt_padded_vec<P: Padding<Self::BlockSize>>(self, msg: &[u8]) -> Vec<u8> {
use crypto_common::typenum::Unsigned;
let bs = Self::BlockSize::USIZE;
let mut out = vec![0; bs * (msg.len() / bs + 1)];
let len = self
.encrypt_padded_b2b::<P>(msg, &mut out)
.expect("enough space for encrypting is allocated")
.len();
out.truncate(len);
out
}
}
pub trait BlockModeDecrypt: BlockSizeUser + Sized {
fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure<BlockSize = Self::BlockSize>);
#[inline]
fn decrypt_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) {
self.decrypt_with_backend(BlockCtx { block });
}
#[inline]
fn decrypt_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) {
self.decrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn decrypt_block(&mut self, block: &mut Block<Self>) {
let block = block.into();
self.decrypt_with_backend(BlockCtx { block });
}
#[inline]
fn decrypt_block_b2b(&mut self, in_block: &Block<Self>, out_block: &mut Block<Self>) {
let block = (in_block, out_block).into();
self.decrypt_with_backend(BlockCtx { block });
}
#[inline]
fn decrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
let blocks = blocks.into();
self.decrypt_with_backend(BlocksCtx { blocks });
}
#[inline]
fn decrypt_blocks_b2b(
&mut self,
in_blocks: &[Block<Self>],
out_blocks: &mut [Block<Self>],
) -> Result<(), NotEqualError> {
InOutBuf::new(in_blocks, out_blocks)
.map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks }))
}
#[cfg(feature = "block-padding")]
#[inline]
fn decrypt_padded_inout<'out, P: Padding<Self::BlockSize>>(
mut self,
data: InOutBuf<'_, 'out, u8>,
) -> Result<&'out [u8], UnpadError> {
let (mut blocks, tail) = data.into_chunks();
if !tail.is_empty() {
return Err(UnpadError);
}
self.decrypt_blocks_inout(blocks.reborrow());
P::unpad_blocks(blocks.into_out())
}
#[cfg(feature = "block-padding")]
#[inline]
fn decrypt_padded<P: Padding<Self::BlockSize>>(
self,
buf: &mut [u8],
) -> Result<&[u8], UnpadError> {
self.decrypt_padded_inout::<P>(buf.into())
}
#[cfg(feature = "block-padding")]
#[inline]
fn decrypt_padded_b2b<'a, P: Padding<Self::BlockSize>>(
self,
in_buf: &[u8],
out_buf: &'a mut [u8],
) -> Result<&'a [u8], UnpadError> {
if out_buf.len() < in_buf.len() {
return Err(UnpadError);
}
let n = in_buf.len();
let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?;
self.decrypt_padded_inout::<P>(buf)
}
#[cfg(all(feature = "block-padding", feature = "alloc"))]
#[inline]
fn decrypt_padded_vec<P: Padding<Self::BlockSize>>(
self,
buf: &[u8],
) -> Result<Vec<u8>, UnpadError> {
let mut out = vec![0; buf.len()];
let len = self.decrypt_padded_b2b::<P>(buf, &mut out)?.len();
out.truncate(len);
Ok(out)
}
}