use aes::Aes128;
use aes::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
use crate::crypto::ecb::BLOCK_SIZE;
pub fn mul_alpha_le(t: [u8; 16]) -> [u8; 16] {
let mut x = u128::from_le_bytes(t);
let carry = (x >> 127) & 1;
x <<= 1;
if carry == 1 {
x ^= 0x87;
}
x.to_le_bytes()
}
pub fn tweak_block(sector: u64) -> [u8; 16] {
let mut b = [0u8; 16];
b[8..].copy_from_slice(§or.to_be_bytes());
b
}
pub fn crypt(
key1: &[u8; 16],
key2: &[u8; 16],
sector_size: usize,
start_sector: u64,
buf: &mut [u8],
decrypt: bool,
) {
assert!(
buf.len().is_multiple_of(BLOCK_SIZE),
"xtsn: buffer not block aligned"
);
assert!(
sector_size > 0 && sector_size.is_multiple_of(BLOCK_SIZE),
"xtsn: bad sector size"
);
let k1 = Aes128::new(key1.into());
let k2 = Aes128::new(key2.into());
for (sector, data) in (start_sector..).zip(buf.chunks_mut(sector_size)) {
let mut tweak = tweak_block(sector);
k2.encrypt_block((&mut tweak).into());
for block in data.as_chunks_mut::<BLOCK_SIZE>().0 {
let mut b = Array::from(std::array::from_fn::<u8, 16, _>(|i| block[i] ^ tweak[i]));
if decrypt {
k1.decrypt_block(&mut b);
} else {
k1.encrypt_block(&mut b);
}
*block = std::array::from_fn(|i| b[i] ^ tweak[i]);
tweak = mul_alpha_le(tweak);
}
}
}
pub fn crypt_with_32byte_key(
key: &[u8; 32],
sector_size: usize,
start_sector: u64,
buf: &mut [u8],
decrypt: bool,
) {
let k1: [u8; 16] = key[..16].try_into().unwrap();
let k2: [u8; 16] = key[16..].try_into().unwrap();
crypt(&k1, &k2, sector_size, start_sector, buf, decrypt);
}