EAX Mode
Documentation |
#include <cryptopp/eax.h>
|
EAX mode of operation is an AEAD mode of operation. It provides both confidentiality and authenticity, and authentication assurances on additional data. EAX is the work of Bellare, Rogaway, and Wagner. The mode was presented in A Conventional Authenticated-Encryption Mode. EAX was a candidate during NIST's Authenticated Encryption Mode selection process.
Additional modes of operation, such as CCM and GCM, offer encryption and authentication. Both CCM and GCM are NIST approved standards, while EAX was not selected. If NIST approval is not required, EAX is superior to CCM in many respects. However, GCM trumps EAX since it is NIST approved and supports parallelization. For a comparison of 4th generation authenticated encryption modes, visit AEAD Comparison.
EAX mode is an n-bit mode of operation. This allow the mode to operate on AES with 128 bits or SHACAL-2 with its 256 bit block size. EAX is online, meaning the data does not need to be known in advance - it can be streamed into the object (there are some practical implementation constraints). Unlike both CCM and GCM, EAX handles messages of arbitrary length.
The tag generated by the mode is from 0 bytes to that of the underlying block cipher size. If the block cipher is AES, the maximum tag size is 16 bytes; if SHACAL-2, the tag length can be no greater than 32 bytes.
Crypto++ offers several modes of operation, including ECB, CBC, OFB, CFB, CBC-CTS, CTR, XTS, CCM, EAX, GCM and OCB.
Crypto++ does not provide a way to retrieve the current IV or counter used for encryption or decryption. If you need the current IV or counter then you need to manage it yourself. Some ciphers allow you to seek a number of bytes or blocks in the stream.
If you are used to working in languages like Java or libraries like OpenSSL, then you might want to visit the Init-Update-Final wiki page. Crypto++ provides the transformation model, but its not obvious because its often shrouded behind Pipelines.
Background
Given two message inputs, additional authenticated data (AAD) and plain text data, EAX mode will provide authentication assurances over the AAD and provide both confidentiality and authentication over the plain text data. Note that either AAD or plain text data may be NULL or unused, but at least one must be present. An simple example would be communications over the internet: the message sent would be the pair { iv, ciphertext }. The iv would be authenticated (and sent in the clear), while the cipher text would have both encryption and authentication applied.
The output of the mode is a single cipher text message which has two components: the concatenated pair { Encrypted, Tag }. Encrypted is the result of encrypting the plain text data, while Tag is a truncation of the authentication code (MAC) over both the AAD and plain text data. Since the tag size is a compile time constant, it is trivial to split the cipher text data into constituent components. Note that the original AAD is not returned in this operation - only the cipher text and tag.
Crypto++ Implementation
Crypto++ 5.6 introduced a new interface for working with authenticated encryption objects: AuthenticatedSymmetricCipher
. Crypto++ exposes EAX through the use of a EAX mode object and a pair of filters: AuthenticatedEncryptionFilter
and AuthenticatedEncryptionFilter
. Each filter combines a block cipher operated in EAX mode with a HashFilter
to generate the MAC and and a HashVerificationFilter
to verify the digest. In addition to EAX mode, CCM Mode and GCM Mode also use the interface.
Both the AAD and plain text data should be fully available to the AuthenticatedSymmetricCipher
objects ensure compatibility with other authenticate and encrypt modes such as CCM. With this in mind, changing modes to evaluate performance will be a trivial task. As with and CCM and GCM, operations on the channel data must be performed in strict order.
The parameters which must be supplied and used by both parties are:
- key and key size
- iv and iv size
- tag size
Finally, do not use a StreamTransformationFilter
on a EAX object to recover only the primary data channel (the cipher text). The StreamTransformationFilter
will throw an exception.
Sample Programs
Two sample programs are provided for EAX mode. In the samples below, a few points are noteworthy:
- The IV/Nonce size can be any size
- A call to
SpecifyDataLengths
is not required - Pushing data into the objects in the wrong order will result in an exception
- Data flow into the encryptor is slightly different than data flow into the decryptor/verifier
- Exceptions for a verification failure can be supressed by not including
THROW_EXCEPTION
flag during construction. - Tag size is altered by specifying a supported value for the
truncatedDigestSize
parameter of eitherAuthenticatedEncryptionFilter
orAuthenticatedDecryptionFilter
. The value is specified in bytes, not bits
EAX test vectors can be found under Dr. Rogaways publications at UC davis (The EAX Mode of Operation). Crypto++ also provides the test vectors in TestVectors
directory.
AE
The first sample, EAX-AE-Test.zip, performs authenticated encryption. It does not perform authentication over additional authenticated data (AAD). Since only encryption is performed, only access to the default channel is needed. So the code below is similar to what one might expect for other modes such as CBC. The exception is SetKeyWithIV
requires an initialization vector (IV) size.
//////////////////////////////////////////////// // Generate keys AutoSeededRandomPool rng; SecByteBlock key( AES::DEFAULT_KEYLENGTH ); rng.GenerateBlock( key, key.size() ); byte iv[ AES::BLOCKSIZE * 16 ]; rng.GenerateBlock( iv, sizeof(iv) ); //////////////////////////////////////////////// // Encrpytion EAX< AES >::Encryption enc; enc.SetKeyWithIV( key, key.size(), iv, sizeof(iv) ); StringSource ss( plaintext, true, new AuthenticatedEncryptionFilter( enc, new StringSink( ciphertext ) ) // AuthenticatedEncryptionFilter ); // StringSource //////////////////////////////////////////////// // Tamper ciphertext[0] ^= 0x01; //////////////////////////////////////////////// // Decrpytion EAX< AES >::Decryption dec; dec.SetKeyWithIV( key, key.size(), iv, sizeof(iv) ); ArraySource as( ciphertext.data(), ciphertext.size(), true, new AuthenticatedDecryptionFilter( dec, new StringSink( recovered ) ) // AuthenticatedDecryptionFilter ); //ArraySource cout << "Recovered original message" << endl;
AEAD
The second sample, EAX-AEAD-Test.zip, performs authenticated encryption with additional authenticated data. It explicitly uses Put
on the two channels rather than using pipelining. The default data channel provides confidentiality and authentication; the second channel ("AAD"), provides only authentication.
//////////////////////////////////////////////// // Generate keys AutoSeededRandomPool rng; SecByteBlock key( AES::DEFAULT_KEYLENGTH ); rng.GenerateBlock( key, key.size() ); byte iv[ AES::BLOCKSIZE * 16 ]; rng.GenerateBlock( iv, sizeof(iv) ); const int TAG_SIZE = 12; //////////////////////////////////////////////// // Encrpytion EAX< AES >::Encryption e; e.SetKeyWithIV( key, key.size(), iv, sizeof(iv) ); AuthenticatedEncryptionFilter ef( e, NULL, false, TAG_SIZE /* MAC_AT_END */ ); // AuthenticatedEncryptionFilter // AuthenticatedEncryptionFilter::ChannelPut // defines two channels: DEFAULT_CHANNEL and AAD_CHANNEL // DEFAULT_CHANNEL is encrypted and authenticated // channel AAD_CHANNEL is authenticated ef.ChannelPut( AAD_CHANNEL, adata.data(), adata.size() ); ef.ChannelMessageEnd(AAD_CHANNEL); // Authenticated data *must* be pushed before // Confidential/Authenticated data. Otherwise // we must catch the BadState exception ef.ChannelPut( DEFAULT_CHANNEL, pdata.data(), pdata.size() ); ef.ChannelMessageEnd(DEFAULT_CHANNEL); // Remove data from channel n = (size_t)ef.MaxRetrievable(); ciphertext.resize( n ); if( n > 0 ) { ef.Get( ciphertext.data(), ciphertext.size() ); } //////////////////////////////////////////////// // Authenticated Data is sent via clear text radata = adata; //////////////////////////////////////////////// // Tamper // ciphertext[0] ^= 0x01; // radata[0] ^= 0x01; //////////////////////////////////////////////// // Break the cipher text out into it's // components: Encrypted and MAC (MAC_AT_END) string enc = ciphertext.substr( 0, ciphertext.length()-TAG_SIZE ); string tag = ciphertext.substr( ciphertext.length()-TAG_SIZE ); // Sanity checks assert( ciphertext.size() == enc.size() + tag.size() ); assert( enc.size() == pdata.size() ); assert( TAG_SIZE == tag.size() ); //////////////////////////////////////////////// // Decrpytion EAX< AES >::Decryption d; d.SetKeyWithIV( key, key.size(), iv, sizeof(iv) ); AuthenticatedDecryptionFilter df( d, NULL, AuthenticatedDecryptionFilter::DEFAULT_FLAGS, TAG_SIZE /* MAC_AT_END */ ); // AuthenticatedDecryptionFilter // ADATA must be inserted first df.ChannelPut( AAD_CHANNEL, radata.data(), radata.size() ); // PDATA (encrypted) df.ChannelPut( DEFAULT_CHANNEL, enc.data(), enc.size() ); // TAG last on default channel df.ChannelPut( DEFAULT_CHANNEL, tag.data(), tag.size() ); // Finished df.MessageEnd(); // If the object does not throw, here's the only // opportunity to check the data's integrity bool b = df.GetLastResult(); assert( true == b ); // Plain text recovered from enc.data() n = (size_t)df.MaxRetrievable(); rpdata.resize( n ); if( n > 0 ) { df.Get( rpdata.data(), n ); } // All is well - work with data assert( pdata == rpdata ); cout << "Recovered original message" << endl;
In the preceding code, the MAC_AT_END
was implied during construction to indicate that the tag was the last item being inserted into the AuthenticatedDecryptionFilter
. If the tag is to be inserted at the end of the process, the following code would be used. Note that AAD must still be pushed before plain text data.
AuthenticatedDecryptionFilter df( d, NULL, MAC_AT_BEGIN ); df.ChannelPut( DEFAULT_CHANNEL, tag.data(), tag.size() ); df.ChannelPut( AAD_CHANNEL, adata.data(), adata.size() ); df.ChannelPut( DEFAULT_CHANNEL, enc.data(), enc.size() ); // Signal End on both channels df.MessageEnd();
Downloads
EAX-AE-Test.zip - EAX Test using only plain text data
EAX-AEAD-Test.zip - EAX Test using both AAD and plain text data
Blowfish-EAX-Filter.zip - Demonstrates encryption and decryption using Blowfish in EAX mode with filters
Twofish-EAX-Filter.zip - Demonstrates encryption and decryption using Twofish in EAX mode with filters
IDEA-EAX-Filter.zip - Demonstrates encryption and decryption using IDEA in EAX mode with filters
Serpent-EAX-Filter.zip - Demonstrates encryption and decryption using Serpent in EAX mode with filters
Camellia-EAX-Filter.zip - Demonstrates encryption and decryption using Camellia in EAX mode with filters