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 Programs

There are two sample programs below. The first sample program below demonstrates a HMAC with SHA256 using filters (see pipelining). The second sample program uses HashTransformation member functions.

Pipelines

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

HashTransformation

Below is an example of using HashTransformation member functions to calculate a HMAC. Internally, pipelines do this for you.

#include "cryptlib.h"
#include "files.h"
#include "hex.h"
#include "sha.h"
#include "hmac.h"
using namespace CryptoPP;

#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
    const byte m[] = {
      0x5,0x8,0xC,0xE,0x1,0xE,0x6,0x0,0x1,0x1,
      0x1,0x1,0x1,0x1,0x1,0x1,0x6,0x4,0x6,0x1,
      0x7,0x4,0x6,0x1,0x0,0x0,0x0,0x0
    };

    const byte k[] = {
      0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
      0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
      0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
      0x1,0x1
    };

    HexEncoder hex(new FileSink(std::cout));

    HMAC<SHA1> hmac(k, sizeof(k));
    hmac.Update(m, sizeof(m));

    byte d[HMAC<SHA1>::DIGESTSIZE];
    hmac.Final(d);

    std::cout << "Message: ";
    hex.Put(m, sizeof(m));
    hex.MessageEnd();
    std::cout << std::endl;

    std::cout << "Digest: ";
    hex.Put(d, sizeof(d));
    hex.MessageEnd();
    std::cout << std::endl;

    return 0;
}

The program produces the expected output:

$ ./test.exe
Message: 05080C0E010E06000101010101010101060406010704060100000000
Digest: 0EA5E034142BDECC5D3AEC9DE727EE836BF95E1D

Downloads

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