eme2 0.2.0

EME2 (ECB-Mask-ECB) wide-block cipher mode of operation
Documentation
use aes::{Aes128, Aes256};
use cipher::KeyIvInit;
use eme2::{Eme2, Error};
use hex_literal::hex;

type Aes128Eme2 = Eme2<Aes128>;
type Aes256Eme2 = Eme2<Aes256>;

fn test_roundtrip(len: usize) {
    let key = [0x42; 64];
    let tweak = [0x11; 16];

    let mut plaintext = vec![0u8; len];
    for (i, val) in plaintext.iter_mut().enumerate() {
        *val = (i % 256) as u8;
    }

    let mut buf = plaintext.clone();

    let cipher = Aes256Eme2::new(&key.into(), &tweak.into());
    cipher.encrypt(&mut buf).expect("encryption succeeded");

    assert_ne!(buf, plaintext);
    assert_eq!(buf.len(), plaintext.len());

    cipher.decrypt(&mut buf).expect("decryption succeeded");
    assert_eq!(buf, plaintext);
}

#[test]
fn test_exact_block() {
    test_roundtrip(16);
}

#[test]
fn test_multiple_blocks() {
    test_roundtrip(32);
    test_roundtrip(48);
    test_roundtrip(64);
    test_roundtrip(1024);
}

#[test]
fn test_partial_blocks() {
    test_roundtrip(17);
    test_roundtrip(31);
    test_roundtrip(33);
    test_roundtrip(127);
    test_roundtrip(1025);
}

#[test]
fn test_data_too_short() {
    let key = [0x42; 64];
    let tweak = [0x11; 16];
    let cipher = Aes256Eme2::new(&key.into(), &tweak.into());

    let mut buf = vec![0u8; 15];
    let err = cipher
        .encrypt(&mut buf)
        .expect_err("should return error for short data");
    assert_eq!(err, Error::DataTooShort);
}

#[test]
fn test_sprp_avalanche_effect() {
    let key = [0x42; 64];
    let tweak = [0x11; 16];
    let cipher = Aes256Eme2::new(&key.into(), &tweak.into());

    let plaintext = b"This is a message that spans multiple blocks for SPRP test!!";

    let mut buf1 = plaintext.to_vec();
    cipher.encrypt(&mut buf1).expect("encryption succeeded");

    let mut buf2 = buf1.clone();
    buf2[25] ^= 0x01;

    cipher.decrypt(&mut buf1).expect("decryption succeeded");
    cipher.decrypt(&mut buf2).expect("decryption succeeded");

    assert_eq!(&buf1[..], &plaintext[..]);

    let diff_count = buf1.iter().zip(buf2.iter()).filter(|(a, b)| a != b).count();
    assert!(
        diff_count > plaintext.len() / 2,
        "SPRP property failed, diff_count: {}",
        diff_count
    );
}

#[test]
fn test_tweak_separation() {
    let key = [0x42; 64];
    let tweak1 = [0x11; 16];
    let tweak2 = [0x22; 16];

    let plaintext = vec![0xAB; 64];

    let mut buf1 = plaintext.clone();
    let mut buf2 = plaintext.clone();

    let cipher1 = Aes256Eme2::new(&key.into(), &tweak1.into());
    let cipher2 = Aes256Eme2::new(&key.into(), &tweak2.into());

    cipher1.encrypt(&mut buf1).expect("encryption succeeded");
    cipher2.encrypt(&mut buf2).expect("encryption succeeded");

    assert_ne!(buf1, buf2);
}

#[test]
fn test_aes128_compatibility() {
    let key = [0x42; 48];
    let tweak = [0x11; 16];

    let cipher = Aes128Eme2::new(&key.into(), &tweak.into());

    let mut buf = vec![0x00; 32];
    cipher.encrypt(&mut buf).expect("encryption succeeded");
    assert_ne!(buf, vec![0x00; 32]);
    cipher.decrypt(&mut buf).expect("decryption succeeded");
    assert_eq!(buf, vec![0x00; 32]);
}

#[test]
fn test_reference_vectors() {
    // Vector 1: 16 bytes
    let key1 = [0x00; 64];
    let tweak1 = [0x01; 16];
    let pt1 = [0x02; 16];
    let expected_ct1 = hex!("e5b94b661f4219b9752c8a986a42b5a0");

    let cipher1 = Aes256Eme2::new(&key1.into(), &tweak1.into());
    let mut buf1 = pt1.to_vec();
    cipher1.encrypt(&mut buf1).expect("encryption succeeded");
    assert_eq!(buf1, expected_ct1);
    cipher1.decrypt(&mut buf1).expect("decryption succeeded");
    assert_eq!(buf1, pt1);

    // Vector 2: 32 bytes
    let pt2 = [0x02; 32];
    let expected_ct2 = hex!("4b943f4f8734635e7e1cf6dedc89f924562c80b86278484b5fafd14ecc638da5");

    let mut buf2 = pt2.to_vec();
    cipher1.encrypt(&mut buf2).expect("encryption succeeded");
    assert_eq!(buf2, expected_ct2);
    cipher1.decrypt(&mut buf2).expect("decryption succeeded");
    assert_eq!(buf2, pt2);

    // Vector 3: 64 bytes with dynamic generation (IEEE P1619.2 EME2 style)
    let mut key3 = [0u8; 64];
    for (i, val) in key3.iter_mut().enumerate() {
        *val = (i * 3) as u8;
    }

    let mut tweak3 = [0u8; 16];
    for (i, val) in tweak3.iter_mut().enumerate() {
        *val = (i * 7) as u8;
    }

    let mut pt3 = [0u8; 64];
    for (i, val) in pt3.iter_mut().enumerate() {
        *val = i as u8;
    }

    let expected_ct3 = hex!(
        "7edc9955fa53153cf2820dbcfdec93784d5d7ca9789fd29e676316f9418d92b00e9bfdb51495504162571eb94e78b9f0d3a73fa2dcf92c4d22d8d8816433b2e7"
    );

    let cipher3 = Aes256Eme2::new(&key3.into(), &tweak3.into());
    let mut buf3 = pt3.to_vec();
    cipher3.encrypt(&mut buf3).expect("encryption succeeded");
    assert_eq!(buf3, expected_ct3);
    cipher3.decrypt(&mut buf3).expect("decryption succeeded");
    assert_eq!(buf3, pt3);
}

#[test]
fn test_reference_vectors_emestar() {
    // Vector 3: 64 bytes with dynamic generation (EME* style)
    let mut key3 = [0u8; 64];
    for (i, val) in key3.iter_mut().enumerate() {
        *val = (i * 3) as u8;
    }

    let mut tweak3 = [0u8; 16];
    for (i, val) in tweak3.iter_mut().enumerate() {
        *val = (i * 7) as u8;
    }

    let mut pt3 = [0u8; 64];
    for (i, val) in pt3.iter_mut().enumerate() {
        *val = i as u8;
    }

    let expected_ct3 = hex!(
        "94415e16e8af1147ea93fa9107d0cf36f1891f00920201635423f733b4e8e47b2e84683168e034cffbea074b688d1582f7d5564fa00450c7856e676f2bb58951"
    );

    let mut cipher3 = <Aes256Eme2 as cipher::KeyInit>::new(&key3.into());
    let t_star = cipher3.hash_ad_emestar(&tweak3);
    cipher3.set_tweak(t_star);

    let mut buf3 = pt3.to_vec();
    cipher3.encrypt(&mut buf3).expect("encryption succeeded");
    assert_eq!(buf3, expected_ct3);
    cipher3.decrypt(&mut buf3).expect("decryption succeeded");
    assert_eq!(buf3, pt3);
}