use aria::cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
use aria::{Aria128, Aria192, Aria256};
use tc_block_cipher::{
BlockCipher, BlockCipherInit, BlockError, CipherDirection, InitError, KeyParams,
};
use crate::BLOCK_BYTES;
type Block = aria::cipher::Block<Aria128>;
enum Cipher {
Aria128(Aria128),
Aria192(Aria192),
Aria256(Aria256),
}
pub struct AriaRustCryptoEngine {
cipher: Option<Cipher>,
direction: CipherDirection,
}
impl core::fmt::Display for AriaRustCryptoEngine {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(crate::ALGO_NAME)
}
}
impl AriaRustCryptoEngine {
pub const fn new() -> Self {
Self {
cipher: None,
direction: CipherDirection::Encrypt,
}
}
}
impl Default for AriaRustCryptoEngine {
fn default() -> Self {
Self::new()
}
}
impl<P: KeyParams + ?Sized> BlockCipherInit<P> for AriaRustCryptoEngine {
type Error = InitError;
fn init(&mut self, direction: CipherDirection, params: &P) -> Result<(), InitError> {
let key = params.key();
let invalid = |_| InitError::InvalidKeyLength(key.len());
let cipher = match key.len() {
16 => Cipher::Aria128(Aria128::new_from_slice(key).map_err(invalid)?),
24 => Cipher::Aria192(Aria192::new_from_slice(key).map_err(invalid)?),
32 => Cipher::Aria256(Aria256::new_from_slice(key).map_err(invalid)?),
len => return Err(InitError::InvalidKeyLength(len)),
};
self.cipher = Some(cipher);
self.direction = direction;
Ok(())
}
}
impl BlockCipher for AriaRustCryptoEngine {
type Error = BlockError;
fn block_size(&self) -> usize {
BLOCK_BYTES
}
fn process_block(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, BlockError> {
let cipher = self.cipher.as_ref().ok_or(BlockError::NotInitialised)?;
let (Some(input), Some(output)) = (
input.get(..BLOCK_BYTES).and_then(Block::slice_as_array),
output
.get_mut(..BLOCK_BYTES)
.and_then(Block::slice_as_mut_array),
) else {
return Err(BlockError::BufferTooShort);
};
match (cipher, self.direction) {
(Cipher::Aria128(c), CipherDirection::Encrypt) => c.encrypt_block_b2b(input, output),
(Cipher::Aria128(c), CipherDirection::Decrypt) => c.decrypt_block_b2b(input, output),
(Cipher::Aria192(c), CipherDirection::Encrypt) => c.encrypt_block_b2b(input, output),
(Cipher::Aria192(c), CipherDirection::Decrypt) => c.decrypt_block_b2b(input, output),
(Cipher::Aria256(c), CipherDirection::Encrypt) => c.encrypt_block_b2b(input, output),
(Cipher::Aria256(c), CipherDirection::Decrypt) => c.decrypt_block_b2b(input, output),
}
Ok(BLOCK_BYTES)
}
}