use core::fmt;
use tc_block_cipher::{
BlockCipher, BlockCipherInit, BlockError, CipherDirection, InitError, KeyParams,
};
use tc_zeroize::Zeroize;
use crate::cipher::{des_func, generate_working_key};
use crate::{BLOCK_BYTES, DES_ALGO_NAME, DES_EDE_ALGO_NAME, EDE2_KEY_BYTES, EDE3_KEY_BYTES};
pub struct DesTableEngine {
working_key: [u32; 32],
initialised: bool,
}
impl DesTableEngine {
pub const fn new() -> Self {
Self {
working_key: [0; 32],
initialised: false,
}
}
}
impl Default for DesTableEngine {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for DesTableEngine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(DES_ALGO_NAME)
}
}
impl Drop for DesTableEngine {
fn drop(&mut self) {
self.working_key.zeroize();
}
}
impl BlockCipher for DesTableEngine {
type Error = BlockError;
fn block_size(&self) -> usize {
BLOCK_BYTES
}
fn process_block(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, BlockError> {
if !self.initialised {
return Err(BlockError::NotInitialised);
}
if input.len() < BLOCK_BYTES || output.len() < BLOCK_BYTES {
return Err(BlockError::BufferTooShort);
}
let mut high = u32::from_be_bytes(input[..4].try_into().unwrap());
let mut low = u32::from_be_bytes(input[4..BLOCK_BYTES].try_into().unwrap());
des_func(&self.working_key, &mut high, &mut low);
output[..4].copy_from_slice(&high.to_be_bytes());
output[4..BLOCK_BYTES].copy_from_slice(&low.to_be_bytes());
Ok(BLOCK_BYTES)
}
}
impl<P: KeyParams + ?Sized> BlockCipherInit<P> for DesTableEngine {
type Error = InitError;
fn init(&mut self, direction: CipherDirection, params: &P) -> Result<(), InitError> {
let key = params.key();
let key: &[u8; 8] = key
.try_into()
.map_err(|_| InitError::InvalidKeyLength(key.len()))?;
self.working_key.zeroize();
let mut expanded = generate_working_key(direction == CipherDirection::Encrypt, key);
self.working_key.copy_from_slice(&expanded);
expanded.zeroize();
self.initialised = true;
Ok(())
}
}
pub struct DesEdeTableEngine {
working_key1: [u32; 32],
working_key2: [u32; 32],
working_key3: [u32; 32],
for_encryption: bool,
initialised: bool,
}
impl DesEdeTableEngine {
pub const fn new() -> Self {
Self {
working_key1: [0; 32],
working_key2: [0; 32],
working_key3: [0; 32],
for_encryption: false,
initialised: false,
}
}
}
impl Default for DesEdeTableEngine {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for DesEdeTableEngine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(DES_EDE_ALGO_NAME)
}
}
impl Drop for DesEdeTableEngine {
fn drop(&mut self) {
self.working_key1.zeroize();
self.working_key2.zeroize();
self.working_key3.zeroize();
}
}
impl BlockCipher for DesEdeTableEngine {
type Error = BlockError;
fn block_size(&self) -> usize {
BLOCK_BYTES
}
fn process_block(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, BlockError> {
if !self.initialised {
return Err(BlockError::NotInitialised);
}
if input.len() < BLOCK_BYTES || output.len() < BLOCK_BYTES {
return Err(BlockError::BufferTooShort);
}
let mut high = u32::from_be_bytes(input[..4].try_into().unwrap());
let mut low = u32::from_be_bytes(input[4..BLOCK_BYTES].try_into().unwrap());
if self.for_encryption {
des_func(&self.working_key1, &mut high, &mut low);
des_func(&self.working_key2, &mut high, &mut low);
des_func(&self.working_key3, &mut high, &mut low);
} else {
des_func(&self.working_key3, &mut high, &mut low);
des_func(&self.working_key2, &mut high, &mut low);
des_func(&self.working_key1, &mut high, &mut low);
}
output[..4].copy_from_slice(&high.to_be_bytes());
output[4..BLOCK_BYTES].copy_from_slice(&low.to_be_bytes());
Ok(BLOCK_BYTES)
}
}
impl<P: KeyParams + ?Sized> BlockCipherInit<P> for DesEdeTableEngine {
type Error = InitError;
fn init(&mut self, direction: CipherDirection, params: &P) -> Result<(), InitError> {
let for_encryption = direction == CipherDirection::Encrypt;
let key = params.key();
if key.len() != EDE2_KEY_BYTES && key.len() != EDE3_KEY_BYTES {
return Err(InitError::InvalidKeyLength(key.len()));
}
let key1: &[u8; 8] = key[..8].try_into().unwrap();
let key2: &[u8; 8] = key[8..16].try_into().unwrap();
let key3: &[u8; 8] = if key.len() == EDE3_KEY_BYTES {
key[16..24].try_into().unwrap()
} else {
key1
};
self.working_key1.zeroize();
let mut expanded = generate_working_key(for_encryption, key1);
self.working_key1.copy_from_slice(&expanded);
expanded.zeroize();
self.working_key2.zeroize();
let mut expanded = generate_working_key(!for_encryption, key2);
self.working_key2.copy_from_slice(&expanded);
expanded.zeroize();
self.working_key3.zeroize();
let mut expanded = generate_working_key(for_encryption, key3);
self.working_key3.copy_from_slice(&expanded);
expanded.zeroize();
self.for_encryption = for_encryption;
self.initialised = true;
Ok(())
}
}