use core::fmt;
use tc_block_cipher::{
BlockCipher, BlockCipherInit, BlockError, CipherDirection, InitError, KeyParams,
};
use tc_zeroize::Zeroize;
use crate::{ALGO_NAME, cipher};
pub struct Dstu7624Engine<const BLOCK_WORDS: usize> {
cipher: cipher::Dstu7624Cipher<BLOCK_WORDS>,
direction: CipherDirection,
initialised: bool,
}
pub type Dstu7624Engine128 = Dstu7624Engine<2>;
pub type Dstu7624Engine256 = Dstu7624Engine<4>;
pub type Dstu7624Engine512 = Dstu7624Engine<8>;
macro_rules! impl_engine {
($block_words:literal, [$($key_bytes:literal),+ $(,)?]) => {
impl Dstu7624Engine<$block_words> {
pub const fn new() -> Self {
Self {
cipher: cipher::Dstu7624Cipher::new(),
direction: CipherDirection::Encrypt,
initialised: false,
}
}
}
impl Default for Dstu7624Engine<$block_words> {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for Dstu7624Engine<$block_words> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(ALGO_NAME)
}
}
impl BlockCipher for Dstu7624Engine<$block_words> {
type Error = BlockError;
fn block_size(&self) -> usize {
$block_words * 8
}
fn process_block(
&mut self,
input: &[u8],
output: &mut [u8],
) -> Result<usize, BlockError> {
if !self.initialised {
return Err(BlockError::NotInitialised);
}
let block_bytes = self.block_size();
if input.len() < block_bytes || output.len() < block_bytes {
return Err(BlockError::BufferTooShort);
}
match self.direction {
CipherDirection::Encrypt => self.cipher.encrypt_block(input, output),
CipherDirection::Decrypt => self.cipher.decrypt_block(input, output),
}
Ok(block_bytes)
}
}
impl<P: KeyParams + ?Sized> BlockCipherInit<P> for Dstu7624Engine<$block_words> {
type Error = InitError;
fn init(
&mut self,
direction: CipherDirection,
params: &P,
) -> Result<(), InitError> {
let key = params.key();
if ![$($key_bytes),+].contains(&key.len()) {
return Err(InitError::InvalidKeyLength(key.len()));
}
self.cipher.set_key(key);
self.direction = direction;
self.initialised = true;
Ok(())
}
}
};
}
impl_engine!(2, [16, 32]);
impl_engine!(4, [32, 64]);
impl_engine!(8, [64]);
impl<const BLOCK_WORDS: usize> Drop for Dstu7624Engine<BLOCK_WORDS> {
fn drop(&mut self) {
self.cipher.zeroize();
}
}