eme2
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.
⚠️ 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.
Standards and Specifications
This crate implements IEEE Std 1619.2 EME2-AES, which is the original academic EME*
specification instantiated with a 128-bit block cipher and a concrete key schedule (one master
key split into Key1/Key2/Key3) in place of EME*'s independent masks L and R. The two specs
describe the same algorithm and share a single implementation here (hash_ad, encrypt_with_ad,
decrypt_with_ad, etc. — there are no separate _eme2/_emestar-suffixed methods). Note that
the two documents disagree on byte order for the underlying GF(2^128) doubling (IEEE's
Mult-by-alpha is little-endian; EME*'s 2L is defined msb-first), so EME* and EME2-AES
ciphertexts are not byte-for-byte interchangeable even though the algorithm is identical. This
crate follows the IEEE convention throughout.
Reference Documents
- EME2 (Standard): IEEE Std 1619.2-2010: IEEE Standard for Wide-Block Encryption for Shared Storage Media (located at
docs/eme2-ieee.pdf, which is an unpublished draft — verify against the published standard before relying on it for interop) - EME* (Academic Paper): "EME*: extending EME to handle arbitrary-length messages with associated data" (Shai Halevi, 2004) (located at
docs/2004-125.pdf)
Cipher Compatibility
By default, this crate ONLY supports block ciphers with a 16-byte (128-bit) block size.
EME2 mathematically requires a 128-bit polynomial for its internal tweak processing. Ciphers with larger block sizes (such as Threefish256, Threefish512, or Threefish1024) are structurally incompatible with the default Eme2<C> 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-128aes-256serpent
extended feature: 256/512/1024-bit blocks
The extended feature adds eme2::extended::Eme2<C>, a generalized version of the same
algorithm that accepts any block cipher with a matching EmePoly implementation — currently
128-, 256-, 512-, and 1024-bit blocks (e.g. Threefish256/512/1024). For 128-bit ciphers it
produces byte-identical output to the base Eme2<C> (verified by test).
[!WARNING] This goes beyond IEEE Std 1619.2, which only defines EME2-AES for 128-bit blocks. The 256/512/1024-bit GF(2^n) moduli are not from any published standard. Each one has been verified irreducible over GF(2) (so the field arithmetic itself is sound), but EME*'s security proof also requires the doubling element to be primitive — order exactly
2^n − 1— which is what the IEEE 128-bit polynomial was specifically chosen for. Primitivity for the larger moduli is not independently verified: it requires the complete prime factorization of2^n − 1, which for n = 1024 is not public knowledge. Treat block sizes above 128 bits as experimental until this is established or the constants are replaced with a citable reference. See theeme2::extendedmodule docs for details.
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 = new;
// EME2 Mode Initialization
let cipher = new;
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; // Handles both encryption and decryption
// Wide-Block Ciphers (EME2)
cipher.encrypt.expect;
cipher.decrypt.expect;
Usage Examples
1. Encryption with a tweak
use Aes256;
use KeyIvInit;
use Eme2;
type Aes256Eme2 = ;
let key = ; // Partitioned internally into Key1, Key2, and Key3
let tweak = ;
let mut data = vec!;
// Initialization using KeyIvInit trait (hashes the tweak via `Eme2::hash_ad`)
let cipher = new;
cipher.encrypt.expect;
cipher.decrypt.expect;
2. Encryption with associated data
use Aes256;
use KeyInit;
use Eme2;
type Aes256Eme2 = ;
let key = ;
let mut data = vec!;
let cipher = new;
let associated_data = b"associated data";
cipher.encrypt_with_ad.expect;
cipher.decrypt_with_ad.expect;
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.