use super::{BlockCipher, InvalidLength};
#[inline]
fn double_tweak(t: &mut [u8; 16]) {
let mut carry = 0u8;
for byte in t.iter_mut() {
let b = *byte;
*byte = (b << 1) | carry;
carry = b >> 7;
}
t[0] ^= 0u8.wrapping_sub(carry) & 0x87;
}
#[derive(Clone)]
pub struct Xts<C: BlockCipher> {
cipher_data: C,
cipher_tweak: C,
}
impl<C: BlockCipher> Xts<C> {
pub fn new(cipher_data: C, cipher_tweak: C) -> Self {
Self {
cipher_data,
cipher_tweak,
}
}
fn initial_tweak(&self, sector_index: u128) -> [u8; 16] {
let mut t = sector_index.to_le_bytes();
self.cipher_tweak.encrypt_block(&mut t);
t
}
pub fn encrypt_sector(&self, sector_index: u128, buf: &mut [u8]) -> Result<(), InvalidLength> {
if buf.len() < 16 {
return Err(InvalidLength);
}
let mut t = self.initial_tweak(sector_index);
let n_full = buf.len() / 16;
let rem = buf.len() % 16;
let full_to_emit = if rem == 0 { n_full } else { n_full - 1 };
let mut block = [0u8; 16];
for i in 0..full_to_emit {
let off = i * 16;
block.copy_from_slice(&buf[off..off + 16]);
xex(&self.cipher_data, &mut block, &t, true);
buf[off..off + 16].copy_from_slice(&block);
double_tweak(&mut t);
}
if rem == 0 {
return Ok(());
}
let full_off = full_to_emit * 16;
block.copy_from_slice(&buf[full_off..full_off + 16]);
xex(&self.cipher_data, &mut block, &t, true);
let mut cc = block;
double_tweak(&mut t);
let mut pp = [0u8; 16];
pp[..rem].copy_from_slice(&buf[full_off + 16..]);
pp[rem..].copy_from_slice(&cc[rem..]);
xex(&self.cipher_data, &mut pp, &t, true);
buf[full_off..full_off + 16].copy_from_slice(&pp);
let _ = &mut cc; buf[full_off + 16..].copy_from_slice(&cc[..rem]);
Ok(())
}
pub fn decrypt_sector(&self, sector_index: u128, buf: &mut [u8]) -> Result<(), InvalidLength> {
if buf.len() < 16 {
return Err(InvalidLength);
}
let mut t = self.initial_tweak(sector_index);
let n_full = buf.len() / 16;
let rem = buf.len() % 16;
let full_to_emit = if rem == 0 { n_full } else { n_full - 1 };
let mut block = [0u8; 16];
for i in 0..full_to_emit {
let off = i * 16;
block.copy_from_slice(&buf[off..off + 16]);
xex(&self.cipher_data, &mut block, &t, false);
buf[off..off + 16].copy_from_slice(&block);
double_tweak(&mut t);
}
if rem == 0 {
return Ok(());
}
let full_off = full_to_emit * 16;
let mut t_next = t;
double_tweak(&mut t_next);
let mut pp = [0u8; 16];
pp.copy_from_slice(&buf[full_off..full_off + 16]);
xex(&self.cipher_data, &mut pp, &t_next, false);
let mut cc = [0u8; 16];
cc[..rem].copy_from_slice(&buf[full_off + 16..]);
cc[rem..].copy_from_slice(&pp[rem..]);
xex(&self.cipher_data, &mut cc, &t, false);
buf[full_off..full_off + 16].copy_from_slice(&cc);
buf[full_off + 16..].copy_from_slice(&pp[..rem]);
Ok(())
}
}
#[inline]
fn xex<C: BlockCipher>(cipher: &C, block: &mut [u8; 16], t: &[u8; 16], encrypt: bool) {
for i in 0..16 {
block[i] ^= t[i];
}
if encrypt {
cipher.encrypt_block(block);
} else {
cipher.decrypt_block(block);
}
for i in 0..16 {
block[i] ^= t[i];
}
}
pub type Aes128Xts = Xts<super::Aes128>;
pub type Aes256Xts = Xts<super::Aes256>;
#[cfg(test)]
mod tests {
use super::*;
use crate::cipher::{Aes128, Aes256};
use crate::test_util::from_hex;
#[test]
fn ieee_1619_vector_1() {
let k1 = from_hex::<16>("00000000000000000000000000000000");
let k2 = from_hex::<16>("00000000000000000000000000000000");
let pt = from_hex::<32>("0000000000000000000000000000000000000000000000000000000000000000");
let expected =
from_hex::<32>("917cf69ebd68b2ec9b9fe9a3eadda692cd43d2f59598ed858c02c2652fbf922e");
let xts = Aes128Xts::new(Aes128::new(&k1), Aes128::new(&k2));
let mut buf = pt;
xts.encrypt_sector(0, &mut buf).unwrap();
assert_eq!(buf, expected);
xts.decrypt_sector(0, &mut buf).unwrap();
assert_eq!(buf, pt);
}
#[test]
fn ieee_1619_vector_2() {
let k1 = from_hex::<16>("11111111111111111111111111111111");
let k2 = from_hex::<16>("22222222222222222222222222222222");
let pt = from_hex::<32>("4444444444444444444444444444444444444444444444444444444444444444");
let expected =
from_hex::<32>("c454185e6a16936e39334038acef838bfb186fff7480adc4289382ecd6d394f0");
let xts = Aes128Xts::new(Aes128::new(&k1), Aes128::new(&k2));
let mut buf = pt;
xts.encrypt_sector(0x3333333333, &mut buf).unwrap();
assert_eq!(buf, expected);
xts.decrypt_sector(0x3333333333, &mut buf).unwrap();
assert_eq!(buf, pt);
}
#[test]
fn ieee_1619_vector_10_aes256() {
let k1 = from_hex::<32>("2718281828459045235360287471352662497757247093699959574966967627");
let k2 = from_hex::<32>("3141592653589793238462643383279502884197169399375105820974944592");
let pt = from_hex::<32>("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
let expected =
from_hex::<32>("1c3b3a102f770386e4836c99e370cf9bea00803f5e482357a4ae12d414a3e63b");
let xts = Aes256Xts::new(Aes256::new(&k1), Aes256::new(&k2));
let mut buf = pt;
xts.encrypt_sector(0xff, &mut buf).unwrap();
assert_eq!(buf, expected);
xts.decrypt_sector(0xff, &mut buf).unwrap();
assert_eq!(buf, pt);
}
#[test]
fn short_sector_rejected() {
let xts = Aes128Xts::new(
Aes128::new(&from_hex::<16>("00000000000000000000000000000000")),
Aes128::new(&from_hex::<16>("00000000000000000000000000000000")),
);
let mut buf = [0u8; 15];
assert_eq!(xts.encrypt_sector(0, &mut buf), Err(InvalidLength));
assert_eq!(xts.decrypt_sector(0, &mut buf), Err(InvalidLength));
}
#[test]
fn cts_roundtrip_all_remainders() {
let k1 = from_hex::<16>("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0");
let k2 = from_hex::<16>("bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0");
let xts = Aes128Xts::new(Aes128::new(&k1), Aes128::new(&k2));
let mut input = [0u8; 47];
for (i, b) in input.iter_mut().enumerate() {
*b = i as u8;
}
for len in 17..=47 {
let mut buf = [0u8; 47];
buf[..len].copy_from_slice(&input[..len]);
let original = buf;
xts.encrypt_sector(0x4242, &mut buf[..len]).unwrap();
assert_ne!(&buf[..len], &original[..len], "ciphertext == plaintext");
xts.decrypt_sector(0x4242, &mut buf[..len]).unwrap();
assert_eq!(&buf[..len], &original[..len]);
}
}
}