use inout::{InOutBuf, NotEqualError};
mod core_api;
mod errors;
#[cfg(feature = "stream-wrapper")]
mod wrapper;
pub use core_api::{
StreamCipherBackend, StreamCipherClosure, StreamCipherCore, StreamCipherCounter,
StreamCipherSeekCore,
};
pub use errors::{OverflowError, StreamCipherError};
#[cfg(feature = "stream-wrapper")]
pub use wrapper::StreamCipherCoreWrapper;
pub trait StreamCipher {
fn check_remaining(&self, data_len: usize) -> Result<(), StreamCipherError>;
fn unchecked_apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>);
fn unchecked_write_keystream(&mut self, buf: &mut [u8]);
#[inline]
fn unchecked_apply_keystream(&mut self, buf: &mut [u8]) {
self.unchecked_apply_keystream_inout(buf.into());
}
#[inline]
fn unchecked_apply_keystream_b2b(
&mut self,
input: &[u8],
output: &mut [u8],
) -> Result<(), NotEqualError> {
let buf = InOutBuf::new(input, output)?;
self.unchecked_apply_keystream_inout(buf);
Ok(())
}
fn try_apply_keystream_inout(
&mut self,
buf: InOutBuf<'_, '_, u8>,
) -> Result<(), StreamCipherError> {
self.check_remaining(buf.len())?;
self.unchecked_apply_keystream_inout(buf);
Ok(())
}
#[inline]
fn try_apply_keystream(&mut self, buf: &mut [u8]) -> Result<(), StreamCipherError> {
self.try_apply_keystream_inout(buf.into())
}
#[inline]
fn try_apply_keystream_b2b(
&mut self,
input: &[u8],
output: &mut [u8],
) -> Result<(), StreamCipherError> {
InOutBuf::new(input, output)
.map_err(|_| StreamCipherError)
.and_then(|buf| self.try_apply_keystream_inout(buf))
}
#[inline]
fn try_write_keystream(&mut self, buf: &mut [u8]) -> Result<(), StreamCipherError> {
self.check_remaining(buf.len())?;
self.unchecked_write_keystream(buf);
Ok(())
}
#[inline]
fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) {
self.try_apply_keystream_inout(buf)
.expect("end of keystream reached");
}
#[inline]
fn apply_keystream(&mut self, buf: &mut [u8]) {
self.try_apply_keystream(buf)
.expect("end of keystream reached");
}
#[inline]
fn apply_keystream_b2b(&mut self, input: &[u8], output: &mut [u8]) {
let Ok(buf) = InOutBuf::new(input, output) else {
panic!("Lengths of input and output buffers are not equal to each other!");
};
self.apply_keystream_inout(buf);
}
#[inline]
fn write_keystream(&mut self, buf: &mut [u8]) {
self.try_write_keystream(buf)
.expect("end of keystream reached");
}
}
pub trait StreamCipherSeek {
fn try_current_pos<T: SeekNum>(&self) -> Result<T, OverflowError>;
fn try_seek<T: SeekNum>(&mut self, pos: T) -> Result<(), StreamCipherError>;
fn current_pos<T: SeekNum>(&self) -> T {
self.try_current_pos()
.expect("position cannot be represented by `T`")
}
fn seek<T: SeekNum>(&mut self, pos: T) {
self.try_seek(pos)
.expect("position value bigger than keystream length");
}
}
impl<C: StreamCipher> StreamCipher for &mut C {
#[inline]
fn check_remaining(&self, data_len: usize) -> Result<(), StreamCipherError> {
C::check_remaining(self, data_len)
}
#[inline]
fn unchecked_apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) {
C::unchecked_apply_keystream_inout(self, buf);
}
#[inline]
fn unchecked_write_keystream(&mut self, buf: &mut [u8]) {
C::unchecked_write_keystream(self, buf);
}
}
pub trait SeekNum: Sized {
fn from_block_byte<T: StreamCipherCounter>(
block: T,
byte: u8,
bs: u8,
) -> Result<Self, OverflowError>;
fn into_block_byte<T: StreamCipherCounter>(self, bs: u8) -> Result<(T, u8), OverflowError>;
}
macro_rules! impl_seek_num {
{$($t:ty )*} => {
$(
impl SeekNum for $t {
fn from_block_byte<T: StreamCipherCounter>(block: T, byte: u8, block_size: u8) -> Result<Self, OverflowError> {
debug_assert!(byte != 0);
let rem = block_size.checked_sub(byte).ok_or(OverflowError)?;
let block: Self = block.try_into().map_err(|_| OverflowError)?;
block
.checked_mul(block_size.into())
.and_then(|v| v.checked_sub(rem.into()))
.ok_or(OverflowError)
}
fn into_block_byte<T: StreamCipherCounter>(self, block_size: u8) -> Result<(T, u8), OverflowError> {
let bs = Self::from(block_size);
let byte = u8::try_from(self % bs).expect("bs fits into u8");
let block = T::try_from(self / bs).map_err(|_| OverflowError)?;
Ok((block, byte))
}
}
)*
};
}
impl_seek_num! { i32 u32 u64 u128 usize }