PHP Implementation of OMAC (One-Key CBC MAC)

About OMAC

OMAC is a blockcipher-based message authentication code designed and analyzed by Professors Tetsu Iwata and Kaoru Kurosawa.

It is documented on the web-page of one of the authors and (also in a quite easy-to-follow manner) in the description of the EAX AEAD (Authenticated Encryption with Additional Data) mode which is available at these locations:

Distinctive features of our implementation in PHP 5:

Behold the ease of usage... the encapsulation... the... Wait a second !

There is no need to know in advance the length of the message to be hashed. The message may be hashed in (consecutive) chunks, by issuing multiple calls to HashData.

One may retrieve the current value of the hash (for all the data fed so far using HashData) at any time and may then continue to feed more data !

This is more flexible than Windows CryptoAPI, which refuses to accept more data to hash (via CryptHashData) once the hash value has been retrieved (via CryptGetHashParam with dwParam == HP_HASHVAL).

The hasher may be reset to the initial state. This is slightly more efficient than creating a new object with the same characteristics. For example, we do not need to re-compute some initial constants.

The user initializes the block cipher with the chosen key via calls to mcrypt_module_open and mcrypt_generic_init and then passes the resource handle to the constructor of OMAC.

Note: The client should set up the cipher in the ECB (Electronic Code-Book) mode (via mcrypt_module_open). The constructor of OMAC checks that ! (-:

Block ciphers with block sizes of 8, 16, 32, 64, 128, 256 or 512 bits are supported.

[2015-01-31] 192-bit block size ciphers are now also supported. Thanks to Axel for pointing out the omission. His web page explains very well how one can obtain the constants for various block sizes.

One can easily add other block sizes by modifying the SHL_GetConstant static function. A hint to obtaining the required constants is provided in the comments for that function.

Of course, since clients may feed data to be hashed in chunks (via multiple calls to HashData), it is easy to provide a prefix for the actual message.

However, the prefixes used by the EAX mode may be specified in an even more direct way. Both the constructor and the Reset function accept an optional argument (of integer type). If it is present, it is used to create a block containing the MSB-first (big-endian) encoding of that value. That block is fed to HashData as a prefix to the message.

Many of the lessons learned with C++ error-safety have been applied here.

Barring failure of string copying, the HashData function is strongly error-safe: either it completely hashes-and/or-saves-for-later-hashing the given message or it has no effect.

In all circumstances, the GetHashEtc function is strongly error-safe, since it does not affect the state of the object at all (by design -- see the "Get-Hash-and-Continue" section above).

We avoid string concatenation on (potentially) long strings (such as chunks of data supplied by the user).

We avoid storing too much state: less than two blocks of "pending data" are stored at any time.

The vectors listed on the website of the designers of the OPAD function have been successfully tested with this implementation.

At least for Rijndael-128, our code seems to work ! (-:

Given that our implementation accepts any block cipher, it can be used to create test vectors for other ciphers.

Because our code is quite easy to follow and understand (after spending a mere two or three months deciphering it), it can be used to reproduce the functionality in other languages and/or environments.

Example of usage:

All the documentation needed to start using our implementation in 5 minutes is contained in a single image ! Just look for new OMAC, $omac->HashData and $omac->GetHash.

Here is a screenshot (using the wonderful EditPlus) of code using OMAC.php to compute some hashes:

Screenshot showing usage

The output of executing that code is shown below:

    The hash for all      40h bytes is 51f0bebf7e3b9d92fc49741779363cfe...
    The hash of the first  Dh bytes is ed80b9a7a5416ca0eab552a413923cc4...
    The hash of the first 1Ah bytes is d065d2dd75af0db03fab54f5a8b09c1c...
    The hash of the first 27h bytes is 2c17844c931c07951592730a34d0d9d2...
    The hash of the first 34h bytes is 168c9b9a221b00d44088a3c14b588567...
    The hash of the first 40h bytes is 51f0bebf7e3b9d92fc49741779363cfe...  

Enough sweet-talk ! Show me the code !

Here you are: ! (-:

The license is:
"All rights reserved and no warranties provided (but you may do whatever you please with the code) !".


For any additional information, you are kindly asked to drop me an email at:
adder_2003 @ yahoo . com

Thou shall address me as "Adder" or, preferably, "Mighty and Magnificent Adder"...

Thank you so much ! (-: