HMAC

From Crypto++ Wiki
Jump to navigation Jump to search
HMAC
Documentation
#include <cryptopp/hmac.h>

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.

All Crypto++ hashes derive from HashTransformation. The base class provides functions like Update, Final and Verify. You can swap-in any hash for any other hash in your program. You can also use ChannelSwitch to send data to multiple hashes at the same time.

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