eme2 0.2.0

EME2 (ECB-Mask-ECB) wide-block cipher mode of operation
Documentation

eme2

Docs Apache2/MIT licensed Rust Version

Generic implementation of the EME2 (ECB-Mask-ECB) wide-block cipher mode of operation.

Mode functionality is accessed using traits from the re-exported cipher crate.

Standards and Specifications

This crate implements both the IEEE Std 1619.2 EME2-AES standard and the original academic EME* specification.

  • IEEE Std 1619.2-2008 (EME2): Dropped the outer XOR with $Key_3$ in the associated data hashing loop for simplicity.
  • Academic EME* (2004): Retains the outer XOR with $Key_3s$ in the associated data hashing loop.

Reference Documents

Cipher Compatibility

This crate ONLY supports block ciphers with a 16-byte (128-bit) block size.

EME2 mathematically requires a 128-bit polynomial ($x{128} + x7 + x^2 + x + 1$) for its internal tweak processing. Ciphers with larger block sizes (such as Threefish256, Threefish512, or Threefish1024) are structurally incompatible with EME2 and are safely rejected at compile time by the crate's generic trait bounds (BlockSizeUser<BlockSize = U16>).

The implementation is explictly tested against standard 128-bit block ciphers to guarantee compatibility across the ecosystem:

  • aes-128
  • aes-256
  • serpent

Migrating from Stream Ciphers (e.g., CTR Mode)

Because eme2 strictly implements RustCrypto's KeyIvInit traits, instantiating the cipher is a 1:1 drop-in replacement for stream ciphers like ctr:

// CTR Mode Initialization
let cipher = Ctr128BE::<Aes128>::new(&key.into(), &nonce.into());

// EME2 Mode Initialization
let cipher = Eme2::<Aes128>::new(&key.into(), &tweak.into());

However, execution differs. Stream ciphers use the StreamCipher trait because their encryption and decryption processes are mathematically identical (XORing a keystream). EME2 is a Wide-Block Cipher, meaning its encryption and decryption passes are mathematically asymmetric. Therefore, it does not implement StreamCipher and instead exposes explicit .encrypt() and .decrypt() methods:

// Stream Ciphers (CTR)
cipher.apply_keystream(&mut data); // Handles both encryption and decryption

// Wide-Block Ciphers (EME2)
cipher.encrypt(&mut data).expect("encryption succeeded");
cipher.decrypt(&mut data).expect("decryption succeeded");

Usage Examples

1. Standard EME2 (IEEE P1619.2)

By default, the KeyIvInit trait and default methods target the IEEE Std 1619.2 (EME2) standard.

use aes::Aes256;
use cipher::{KeyIvInit, KeyInit};
use eme2::Eme2;

type Aes256Eme2 = Eme2<Aes256>;

let key = [0x42; 64]; // Partitioned internally into Key1, Key2, and Key3
let tweak = [0x11; 16];
let mut data = vec![0u8; 64];

// Initialization using KeyIvInit trait (defaults to EME2 tweak hashing)
let cipher = Aes256Eme2::new(&key.into(), &tweak.into());

// Encryption & Decryption
cipher.encrypt(&mut data).expect("encryption succeeded");
cipher.decrypt(&mut data).expect("decryption succeeded");

// Associated Data (EME2 style)
let associated_data = b"associated data";
cipher.encrypt_with_ad_eme2(associated_data, &mut data).expect("encryption succeeded");
cipher.decrypt_with_ad_eme2(associated_data, &mut data).expect("decryption succeeded");

2. EME* Compatibility

For compatibility with systems using the EME* academic specification:

use aes::Aes256;
use cipher::KeyInit;
use eme2::Eme2;

type Aes256Eme2 = Eme2<Aes256>;

let key = [0x42; 64];
let tweak = [0x11; 16];
let mut data = vec![0u8; 64];

// Initialize using the raw KeyInit trait (tweak defaults to all-zeros)
let mut cipher = <Aes256Eme2 as cipher::KeyInit>::new(&key.into());

// Compute the tweak using EME* AD hashing and configure it
let t_star = cipher.hash_ad_emestar(&tweak);
cipher.set_tweak(t_star);

// Encryption & Decryption (with EME* pre-computed tweak)
cipher.encrypt(&mut data).expect("encryption succeeded");
cipher.decrypt(&mut data).expect("decryption succeeded");

// Inline Associated Data (EME* style)
let associated_data = b"associated data";
cipher.encrypt_with_ad_emestar(associated_data, &mut data).expect("encryption succeeded");
cipher.decrypt_with_ad_emestar(associated_data, &mut data).expect("decryption succeeded");

⚠️ Security Warning: Hazmat!

This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity is not verified, which can lead to serious vulnerabilities. It is highly recommended to use EME2 in combination with a strong MAC to provide robust authenticated encryption.

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.