Hmac

From Crypto++ Wiki
Jump to: navigation, search

HMAC is a hash-based MAC algorithm specified in FIPS 198. A HMAC is the hash equivalent of a CMAC. HMACs can be used when a hash function is more readily available than a block cipher.

Sample Program

The sample program below demonstrates a HMAC with SHA256 using filters (see pipelining). The key is declared on the stack and a SecByteBlock is used to ensure the sensitive material is zeroized. Similar could be used for the message if desired.

AutoSeededRandomPool prng;

SecByteBlock key(16);
prng.GenerateBlock(key, key.size());

string plain = "HMAC Test";
string mac, encoded;

/*********************************\
\*********************************/

// Pretty print key
encoded.clear();
StringSource ss1(key, key.size(), true,
    new HexEncoder(
        new StringSink(encoded)
    ) // HexEncoder
); // StringSource

cout << "key: " << encoded << endl;
cout << "plain text: " << plain << endl;

/*********************************\
\*********************************/

try
{
    HMAC< SHA256 > hmac(key, key.size());

    StringSource ss2(plain, true, 
        new HashFilter(hmac,
            new StringSink(mac)
        ) // HashFilter      
    ); // StringSource
}
catch(const CryptoPP::Exception& e)
{
    cerr << e.what() << endl;
    exit(1);
}

/*********************************\
\*********************************/

// Pretty print
encoded.clear();
StringSource ss3(mac, true,
    new HexEncoder(
        new StringSink(encoded)
    ) // HexEncoder
); // StringSource

cout << "hmac: " << encoded << endl;

A typical output is shown below. Note that each run will produce different results because the key is randomly generated.

$ ./Driver.exe
key: 11A47EC4465DD95FCD393075E7D3C4EB
plain text: HMAC Test
hmac: 24DA0BDE78E7E277B42188165595CCEB0DDF303B9EF93534B04C6433DD57EF78

To verify a HMAC on a message, use a HashVerificationFilter.

try
{
    HMAC< SHA256 > hmac(key, key.size());
    const int flags = HashVerificationFilter::THROW_EXCEPTION | HashVerificationFilter::HASH_AT_END;
    
    StringSource(plain + mac, true, 
        new HashVerificationFilter(hmac, NULL, flags)
    ); // StringSource

    cout << "Verified message" << endl;
}
catch(const CryptoPP::Exception& e)
{
    cerr << e.what() << endl;
    ...
}

We can tamper with a message as follows, which will cause the HashVerificationFilter to throw the exception, HashVerificationFilter: message hash or MAC not valid:

HMAC< SHA256 > hmac(key, key.size());

// Tamper with message
plain[0] ^= 0x01;

// Tamper with MAC
mac[0] ^= 0x01;

StringSource(plain + mac, true, 
    new HashVerificationFilter(hmac, NULL, THROW_EXCEPTION | HASH_AT_END)
); // StringSource

Switching to another hash, such as Whirlpool, is a simple as the following:

HMAC< Whirlpool > hmac(key, key.size());

StringSource(plain, true, 
    new HashFilter(hmac,
        new StringSink(mac)
    ) // HashFilter      
); // StringSource

Downloads

HMAC-SHA-Filter.zip - Demonstrates a SHA256 based HMAC with filters