use cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
use crate::error::{CryptoError, Result};
pub trait BlockCipher {
fn encrypt(key: &[u8], block: &mut [u8]) -> Result<()>;
fn decrypt(key: &[u8], block: &mut [u8]) -> Result<()>;
fn block_size() -> usize;
fn key_size() -> usize;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BlockCipherSpec {
pub name: &'static str,
pub block_size: usize,
pub key_size: usize,
}
macro_rules! define_block_ciphers {
(
$(
$(#[$meta:meta])*
$wrapper:ident => {
backend: $cipher:ty,
name: $name:expr,
block: $block_len:expr,
key: $key_len:expr $(,)?
}
),+ $(,)?
) => {
$(
$(#[$meta])*
pub struct $wrapper;
impl $wrapper {
pub const SPEC: BlockCipherSpec = BlockCipherSpec {
name: $name,
block_size: $block_len,
key_size: $key_len,
};
pub const fn spec() -> BlockCipherSpec {
Self::SPEC
}
}
impl BlockCipher for $wrapper {
fn encrypt(key: &[u8], block: &mut [u8]) -> Result<()> {
if block.len() != $block_len {
return Err(CryptoError::InvalidLength);
}
let cipher = <$cipher>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
let arr: [u8; $block_len] =
block.try_into().map_err(|_| CryptoError::InvalidLength)?;
let mut b = cipher::Block::<$cipher>::from(arr);
cipher.encrypt_block(&mut b);
block.copy_from_slice(&b);
Ok(())
}
fn decrypt(key: &[u8], block: &mut [u8]) -> Result<()> {
if block.len() != $block_len {
return Err(CryptoError::InvalidLength);
}
let cipher = <$cipher>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
let arr: [u8; $block_len] =
block.try_into().map_err(|_| CryptoError::InvalidLength)?;
let mut b = cipher::Block::<$cipher>::from(arr);
cipher.decrypt_block(&mut b);
block.copy_from_slice(&b);
Ok(())
}
fn block_size() -> usize {
Self::SPEC.block_size
}
fn key_size() -> usize {
Self::SPEC.key_size
}
}
)+
};
}
define_block_ciphers! {
Aes128Ecb => { backend: aes::Aes128, name: "AES-128-ECB", block: 16, key: 16 },
Aes256Ecb => { backend: aes::Aes256, name: "AES-256-ECB", block: 16, key: 32 },
Sm4Ecb => { backend: sm4::Sm4, name: "SM4-ECB", block: 16, key: 16 },
DesEcb => { backend: des::Des, name: "DES-ECB", block: 8, key: 8 },
Des3Ecb => { backend: des::TdesEde3, name: "3DES-ECB", block: 8, key: 24 },
}