use aes::Aes128;
use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, generic_array::GenericArray};
pub fn aes128_ecb_encrypt_block(data: &[u8; 16], key: &[u8; 16]) -> [u8; 16] {
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut block = GenericArray::clone_from_slice(data);
cipher.encrypt_block(&mut block);
block.into()
}
pub fn aes128_ecb_decrypt_block(data: &[u8; 16], key: &[u8; 16]) -> [u8; 16] {
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut block = GenericArray::clone_from_slice(data);
cipher.decrypt_block(&mut block);
block.into()
}
pub fn aes128_ecb_encrypt(data: &[u8], key: &[u8; 16]) -> Vec<u8> {
assert!(
data.len().is_multiple_of(16),
"Data length must be multiple of 16, got {}",
data.len()
);
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut result = data.to_vec();
for chunk in result.chunks_mut(16) {
let block = GenericArray::from_mut_slice(chunk);
cipher.encrypt_block(block);
}
result
}
pub fn aes128_ecb_decrypt(data: &[u8], key: &[u8; 16]) -> Vec<u8> {
assert!(
data.len().is_multiple_of(16),
"Data length must be multiple of 16, got {}",
data.len()
);
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut result = data.to_vec();
for chunk in result.chunks_mut(16) {
let block = GenericArray::from_mut_slice(chunk);
cipher.decrypt_block(block);
}
result
}
pub fn aes128_cbc_decrypt(data: &[u8], key: &[u8; 16]) -> Vec<u8> {
assert!(
data.len().is_multiple_of(16),
"Data length must be multiple of 16, got {}",
data.len()
);
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut result = Vec::with_capacity(data.len());
let mut iv = GenericArray::from([0u8; 16]);
for chunk in data.chunks(16) {
let mut block = GenericArray::clone_from_slice(chunk);
cipher.decrypt_block(&mut block);
for i in 0..16 {
block[i] ^= iv[i];
}
result.extend_from_slice(&block);
iv.copy_from_slice(chunk);
}
result
}
pub fn aes128_cbc_encrypt(data: &[u8], key: &[u8; 16]) -> Vec<u8> {
assert!(
data.len().is_multiple_of(16),
"Data length must be multiple of 16, got {}",
data.len()
);
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut result = Vec::with_capacity(data.len());
let mut iv = GenericArray::from([0u8; 16]);
for chunk in data.chunks(16) {
let mut block = GenericArray::clone_from_slice(chunk);
for i in 0..16 {
block[i] ^= iv[i];
}
cipher.encrypt_block(&mut block);
result.extend_from_slice(&block);
iv.copy_from_slice(&block);
}
result
}
pub fn aes128_ctr_decrypt(data: &[u8], key: &[u8; 16], nonce: &[u8; 8], offset: u64) -> Vec<u8> {
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut result = Vec::with_capacity(data.len());
let mut counter_val = offset / 16;
let mut block_offset = (offset % 16) as usize;
let mut input_block = [0u8; 16];
input_block[0..8].copy_from_slice(nonce);
let mut data_idx = 0;
while data_idx < data.len() {
input_block[8..16].copy_from_slice(&counter_val.to_be_bytes());
let mut keystream = GenericArray::clone_from_slice(&input_block);
cipher.encrypt_block(&mut keystream);
let available_keystream = 16 - block_offset;
let bytes_to_process = std::cmp::min(available_keystream, data.len() - data_idx);
for i in 0..bytes_to_process {
result.push(data[data_idx + i] ^ keystream[block_offset + i]);
}
data_idx += bytes_to_process;
if block_offset + bytes_to_process == 16 {
counter_val += 1;
block_offset = 0;
} else {
block_offset += bytes_to_process;
}
}
result
}
pub fn aes128_ctr_encrypt(data: &[u8], key: &[u8; 16], nonce: &[u8; 8], offset: u64) -> Vec<u8> {
aes128_ctr_decrypt(data, key, nonce, offset)
}
pub fn chunk_mac_calculate(data: &[u8], key: &[u8; 16], iv: &[u8; 16]) -> [u8; 16] {
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut mac = GenericArray::clone_from_slice(iv);
let chunks = data.chunks(16);
for chunk in chunks {
let mut block = [0u8; 16];
block[..chunk.len()].copy_from_slice(chunk);
for i in 0..16 {
mac[i] ^= block[i];
}
cipher.encrypt_block(&mut mac);
}
mac.into()
}
pub fn meta_mac_calculate(chunk_macs: &[[u8; 16]], key: &[u8; 16]) -> [u8; 16] {
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut meta_mac = GenericArray::from([0u8; 16]);
for chunk_mac in chunk_macs {
for i in 0..16 {
meta_mac[i] ^= chunk_mac[i];
}
cipher.encrypt_block(&mut meta_mac);
}
meta_mac.into()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encrypt_decrypt_block() {
let key = [0u8; 16];
let plaintext = [1u8; 16];
let ciphertext = aes128_ecb_encrypt_block(&plaintext, &key);
let decrypted = aes128_ecb_decrypt_block(&ciphertext, &key);
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_encrypt_decrypt_multiple_blocks() {
let key = [0x42u8; 16];
let plaintext = vec![0xABu8; 32];
let ciphertext = aes128_ecb_encrypt(&plaintext, &key);
let decrypted = aes128_ecb_decrypt(&ciphertext, &key);
assert_eq!(decrypted, plaintext);
}
#[test]
#[should_panic(expected = "Data length must be multiple of 16")]
fn test_encrypt_invalid_length() {
let key = [0u8; 16];
let plaintext = vec![0u8; 15]; aes128_ecb_encrypt(&plaintext, &key);
}
#[test]
fn test_known_vector() {
let key: [u8; 16] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f,
];
let plaintext: [u8; 16] = [
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd,
0xee, 0xff,
];
let expected: [u8; 16] = [
0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4,
0xc5, 0x5a,
];
let ciphertext = aes128_ecb_encrypt_block(&plaintext, &key);
assert_eq!(ciphertext, expected);
}
#[test]
fn test_cbc_decrypt() {
let key = [0u8; 16];
let p1 = [1u8; 16];
let p2 = [1u8; 16];
let c1 = aes128_ecb_encrypt_block(&p1, &key);
let mut p2_xor_c1 = [0u8; 16];
for i in 0..16 {
p2_xor_c1[i] = p2[i] ^ c1[i];
}
let c2 = aes128_ecb_encrypt_block(&p2_xor_c1, &key);
let mut ciphertext = Vec::new();
ciphertext.extend_from_slice(&c1);
ciphertext.extend_from_slice(&c2);
let decrypted = aes128_cbc_decrypt(&ciphertext, &key);
assert_eq!(decrypted[..16], p1);
assert_eq!(decrypted[16..], p2);
}
#[test]
fn test_cbc_encrypt_decrypt() {
let key = [0x12u8; 16];
let plaintext = vec![0xABu8; 32];
let ciphertext = aes128_cbc_encrypt(&plaintext, &key);
let decrypted = aes128_cbc_decrypt(&ciphertext, &key);
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_ctr_encrypt_decrypt() {
let key = [0x55u8; 16];
let nonce = [0xAAu8; 8];
let plaintext = b"Hello Mega World! This is a test of CTR mode.";
let offset = 0;
let ciphertext = aes128_ctr_decrypt(plaintext, &key, &nonce, offset);
let decrypted = aes128_ctr_decrypt(&ciphertext, &key, &nonce, offset);
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_ctr_offset_handling() {
let key = [0x55u8; 16];
let nonce = [0xAAu8; 8];
let plaintext = vec![0x33u8; 100];
let ciphertext = aes128_ctr_decrypt(&plaintext, &key, &nonce, 0);
let split_point = 20;
let mut decrypted = Vec::new();
let part1 = aes128_ctr_decrypt(&ciphertext[..split_point], &key, &nonce, 0);
let part2 =
aes128_ctr_decrypt(&ciphertext[split_point..], &key, &nonce, split_point as u64);
decrypted.extend_from_slice(&part1);
decrypted.extend_from_slice(&part2);
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_chunk_mac_calculate() {
let key = [0x11u8; 16];
let iv = [0x22u8; 16];
let data = vec![0x33u8; 32];
let mut mac = iv;
for i in 0..16 {
mac[i] ^= data[i];
}
let mac = aes128_ecb_encrypt_block(&mac, &key);
let mut mac2 = mac;
for i in 0..16 {
mac2[i] ^= data[16 + i];
}
let mac2 = aes128_ecb_encrypt_block(&mac2, &key);
let calculated = chunk_mac_calculate(&data, &key, &iv);
assert_eq!(calculated, mac2);
}
#[test]
fn test_meta_mac_calculate() {
let key = [0x44u8; 16];
let chunk_mac1 = [0x55u8; 16];
let chunk_mac2 = [0x66u8; 16];
let chunk_macs = vec![chunk_mac1, chunk_mac2];
let mut mac = [0u8; 16];
for i in 0..16 {
mac[i] ^= chunk_mac1[i];
}
let mac = aes128_ecb_encrypt_block(&mac, &key);
let mut mac2 = mac;
for i in 0..16 {
mac2[i] ^= chunk_mac2[i];
}
let mac2 = aes128_ecb_encrypt_block(&mac2, &key);
let calculated = meta_mac_calculate(&chunk_macs, &key);
assert_eq!(calculated, mac2);
}
#[test]
fn test_chunk_mac_pading() {
let key = [0x11u8; 16];
let iv = [0x22u8; 16];
let data = vec![0x33u8; 10];
let mut block = [0u8; 16];
block[..10].copy_from_slice(&data);
let mut mac = iv;
for i in 0..16 {
mac[i] ^= block[i];
}
let mac = aes128_ecb_encrypt_block(&mac, &key);
let calculated = chunk_mac_calculate(&data, &key, &iv);
assert_eq!(calculated, mac);
}
}