eme2-extended
Generic implementation of the EME2 (ECB-Mask-ECB) wide-block cipher mode of operation, extended for generic block sizes.
Mode functionality is accessed using traits from the re-exported cipher crate.
About EME2 and Test Vectors
The official EME2 specification is standardized under IEEE P1619.2. Unfortunately, the official IEEE document and its test vectors are hidden behind a paywall.
Because the official test vectors are not freely available, this implementation was verified using self-generated test vectors derived from reference Python implementations of Shai Halevi's original EME* paper. Despite this limitation, this crate provides a fully-compliant EME2 implementation that handles arbitrary length messages (via ciphertext stealing) and adheres strictly to the $GF(2^{128})$ Galois Field arithmetic specified by the standard.
Cipher Compatibility & EmePoly Compile-Time Safety
This crate supports block ciphers of 128-bit, 256-bit, 512-bit, and 1024-bit sizes.
While the original EME2 standard mathematically limits processing to a 128-bit polynomial ($x{128} + x7 + x^2 + x + 1$), this extended implementation dynamically supports generic block sizes. It achieves this via a custom EmePoly trait that enforces Galois Field polynomial arithmetic strictly at compile time.
Instead of crashing or panicking at runtime, the compiler guarantees that your block cipher size maps to a mathematically proven irreducible polynomial.
This implementation is extensively tested to guarantee compatibility across the ecosystem. It supports standard 128-bit block ciphers:
aes-128aes-256serpent
As well as wide-block ciphers using our generic EmePoly extensions:
Threefish256(256-bit)Threefish512(512-bit)Threefish1024(1024-bit)
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.unwrap;
cipher.decrypt.unwrap;
⚠️ 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 (like BLAKE3) 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.