use alloc::vec::Vec;
use cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit, KeyIvInit, StreamCipher};
use ctr::Ctr128BE;
use crate::{
error::{CryptoError, Result},
streaming_cipher::padding::{pkcs7_pad, pkcs7_unpad},
};
pub fn cbc_encrypt<C>(key: &[u8], iv: &[u8], plaintext: &[u8], block_size: usize) -> Result<Vec<u8>>
where
C: BlockCipherEncrypt + KeyInit,
{
let cipher = C::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
let bs = block_size;
if iv.len() != bs {
return Err(CryptoError::InvalidLength);
}
let mut input = Vec::with_capacity(plaintext.len() + bs);
input.extend_from_slice(plaintext);
pkcs7_pad(&mut input, bs)?;
let mut output = alloc::vec![0u8; input.len()];
let mut prev = iv;
for (i, chunk) in input.chunks(bs).enumerate() {
let mut block: Vec<u8> = chunk.to_vec();
for (a, b) in block.iter_mut().zip(prev.iter()) {
*a ^= b;
}
let mut cipher_block =
cipher::Block::<C>::try_from(&block[..bs]).map_err(|_| CryptoError::InvalidLength)?;
cipher.encrypt_block(&mut cipher_block);
output[i * bs..(i + 1) * bs].copy_from_slice(&cipher_block);
prev = &output[i * bs..(i + 1) * bs];
}
Ok(output)
}
pub fn cbc_decrypt<C>(
key: &[u8],
iv: &[u8],
ciphertext: &[u8],
block_size: usize,
) -> Result<Vec<u8>>
where
C: BlockCipherDecrypt + KeyInit,
{
let cipher = C::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
let bs = block_size;
if iv.len() != bs {
return Err(CryptoError::InvalidLength);
}
if ciphertext.is_empty() || !ciphertext.len().is_multiple_of(bs) {
return Err(CryptoError::InvalidLength);
}
let mut output = alloc::vec![0u8; ciphertext.len()];
let mut prev = iv;
for (i, chunk) in ciphertext.chunks(bs).enumerate() {
let mut cipher_block =
cipher::Block::<C>::try_from(chunk).map_err(|_| CryptoError::InvalidLength)?;
cipher.decrypt_block(&mut cipher_block);
let plain_block = &mut output[i * bs..(i + 1) * bs];
plain_block.copy_from_slice(&cipher_block);
for (a, b) in plain_block.iter_mut().zip(prev.iter()) {
*a ^= b;
}
prev = chunk;
}
pkcs7_unpad(&output, bs)
}
pub fn aes128_cbc_encrypt(key: &[u8], iv: &[u8], pt: &[u8]) -> Result<Vec<u8>> {
cbc_encrypt::<aes::Aes128>(key, iv, pt, 16)
}
pub fn aes128_cbc_decrypt(key: &[u8], iv: &[u8], ct: &[u8]) -> Result<Vec<u8>> {
cbc_decrypt::<aes::Aes128>(key, iv, ct, 16)
}
pub fn aes256_cbc_encrypt(key: &[u8], iv: &[u8], pt: &[u8]) -> Result<Vec<u8>> {
cbc_encrypt::<aes::Aes256>(key, iv, pt, 16)
}
pub fn aes256_cbc_decrypt(key: &[u8], iv: &[u8], ct: &[u8]) -> Result<Vec<u8>> {
cbc_decrypt::<aes::Aes256>(key, iv, ct, 16)
}
pub fn sm4_cbc_encrypt(key: &[u8], iv: &[u8], pt: &[u8]) -> Result<Vec<u8>> {
cbc_encrypt::<sm4::Sm4>(key, iv, pt, 16)
}
pub fn sm4_cbc_decrypt(key: &[u8], iv: &[u8], ct: &[u8]) -> Result<Vec<u8>> {
cbc_decrypt::<sm4::Sm4>(key, iv, ct, 16)
}
pub fn des3_cbc_encrypt(key: &[u8], iv: &[u8], pt: &[u8]) -> Result<Vec<u8>> {
cbc_encrypt::<des::TdesEde3>(key, iv, pt, 8)
}
pub fn des3_cbc_decrypt(key: &[u8], iv: &[u8], ct: &[u8]) -> Result<Vec<u8>> {
cbc_decrypt::<des::TdesEde3>(key, iv, ct, 8)
}
pub fn des_cbc_encrypt(key: &[u8], iv: &[u8], pt: &[u8]) -> Result<Vec<u8>> {
cbc_encrypt::<des::Des>(key, iv, pt, 8)
}
pub fn des_cbc_decrypt(key: &[u8], iv: &[u8], ct: &[u8]) -> Result<Vec<u8>> {
cbc_decrypt::<des::Des>(key, iv, ct, 8)
}
pub fn aes128_ctr(key: &[u8], iv: &[u8], data: &mut [u8]) -> Result<()> {
let mut ctr =
Ctr128BE::<aes::Aes128>::new_from_slices(key, iv).map_err(|_| CryptoError::InvalidKey)?;
ctr.apply_keystream(data);
Ok(())
}
pub fn aes256_ctr(key: &[u8], iv: &[u8], data: &mut [u8]) -> Result<()> {
let mut ctr =
Ctr128BE::<aes::Aes256>::new_from_slices(key, iv).map_err(|_| CryptoError::InvalidKey)?;
ctr.apply_keystream(data);
Ok(())
}
pub fn sm4_ctr(key: &[u8], iv: &[u8], data: &mut [u8]) -> Result<()> {
let mut ctr =
Ctr128BE::<sm4::Sm4>::new_from_slices(key, iv).map_err(|_| CryptoError::InvalidKey)?;
ctr.apply_keystream(data);
Ok(())
}