Skip to content

Instantly share code, notes, and snippets.

@KerfuffleV2
Created April 9, 2022 10:15
Show Gist options
  • Save KerfuffleV2/03b0de1ea8d696b63622d5b64226f1be to your computer and use it in GitHub Desktop.
Save KerfuffleV2/03b0de1ea8d696b63622d5b64226f1be to your computer and use it in GitHub Desktop.
AES CBC thing for /u/PeksyTiger
[package]
name = "testaes"
version = "0.1.0"
edition = "2021"
[dependencies]
aes = { version = "=0.8.1", features = [] }
cipher = { version = "=0.4.3", features = ["block-padding"] }
cbc = { version = "=0.1.2", features = ["block-padding", "std"] }
anyhow = "1"
#![allow(dead_code)]
// PLEASE NOTE: The safety of using the functions in this way is not something
// I can verify personally. It's easy to make serious mistakes using Crypto and
// I am not an expert.
use anyhow::Result;
use aes::{
cipher::{
block_padding::{Padding, Pkcs7},
generic_array::GenericArray,
AlgorithmName, Block, BlockCipher, BlockDecrypt, BlockDecryptMut, BlockEncryptMut, KeyInit,
KeyIvInit,
},
{Aes128, Aes192, Aes256},
};
// Also see: https://docs.rs/cbc/latest/cbc/
pub trait CipherTraitBundle:
BlockCipher + BlockEncryptMut + BlockDecrypt + BlockDecryptMut + AlgorithmName + std::fmt::Debug
{
type Padding: Padding<Self::BlockSize>;
}
impl CipherTraitBundle for Aes128 {
type Padding = Pkcs7;
}
impl CipherTraitBundle for Aes192 {
type Padding = Pkcs7;
}
impl CipherTraitBundle for Aes256 {
type Padding = Pkcs7;
}
#[derive(Debug)]
pub struct Test<CI: CipherTraitBundle> {
enc: cbc::Encryptor<CI>,
dec: cbc::Decryptor<CI>,
}
// I'm assuming you're always using Pkcs7 as the padding. If you want to be able to
// instantiate Test<...> with different types of padding then you probably need to move
// the associated type out of CipherTraitBundle and make your struct take a generic for the padding.
// Example below:
//
// pub struct Test2<CI: CipherTraitBundle, PAD: Padding<CI::BlockSize>> {
// enc: cbc::Encryptor<CI>,
// dec: cbc::Decryptor<CI>,
// _pad_marker: std::marker::PhantomData<*const PAD>,
// }
type TestAes128Cbc = Test<Aes128>;
type TestAes192Cbc = Test<Aes192>;
type TestAes256Cbc = Test<Aes256>;
impl<CI: CipherTraitBundle> Test<CI> {
pub fn new(key: GenericArray<u8, CI::KeySize>, iv: GenericArray<u8, CI::BlockSize>) -> Self
where
CI: KeyInit,
{
// Using new_from_slices is also possible, but it is a fallible function.
// let enc = cbc::Encryptor::<CI>::new_from_slices(&key, &iv).expect("Invalid key/iv");
// let dec = cbc::Decryptor::<CI>::new_from_slices(&key, &iv).expect("Invalid key/iv");
let enc = cbc::Encryptor::<CI>::new(&key, &iv);
let dec = cbc::Decryptor::<CI>::new(&key, &iv);
Self { enc, dec }
}
// The next two functions consume the struct, which may or may not be what you want.
pub fn into_encrypted<R: AsRef<[u8]>>(self, plaintext: R) -> Vec<u8> {
self.enc
.encrypt_padded_vec_mut::<CI::Padding>(plaintext.as_ref())
}
pub fn into_decrypted<R: AsRef<[u8]>>(self, ciphertext: R) -> Result<Vec<u8>> {
self.dec
.decrypt_padded_vec_mut::<CI::Padding>(ciphertext.as_ref())
.map_err(anyhow::Error::from)
}
// These functions will encrypt/decrypt a block in place without consuming the struct.
// You're responsible for making sure the data is in the correct format.
pub fn encrypt_block_mut(&mut self, block: &mut Block<CI>) {
self.enc.encrypt_block_mut(block)
}
pub fn decrypt_block_mut(&mut self, block: &mut Block<CI>) {
self.dec.decrypt_block_mut(block)
}
}
fn main() {
let test_aes128 =
TestAes128Cbc::new(GenericArray::from([0u8; 16]), GenericArray::from([0u8; 16]));
let test_aes192 =
TestAes192Cbc::new(GenericArray::from([0u8; 24]), GenericArray::from([0u8; 16]));
println!("{test_aes128:?}");
println!("{test_aes192:?}");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment