HashVerificationFilter

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

A HashVerificationFilter is a filter that verifies a digest on a message. The companion class is the HashFilter.

The HashVerificationFilter takes a pointer to a BufferedTransformation. Because a pointer is taken, the HashVerificationFilter owns the attached transformation, and therefore will destroy it. See ownership for more details.

Sources, filters and sinks are discussed at Pipelining. The pipeline article explains the design and shows you how to use them.

Construction

HashVerificationFilter (HashTransformation &hm,
                        BufferedTransformation *attachment=NULL,
                        word32 flags=DEFAULT_FLAGS)

hm is a hash, such as Whirlpool or SHA.

attachment is a BufferedTransformation, such as another filter or sink. If attachment is NULL, then the HashVerificationFilter object will internally accumulate the output byte stream.

flags is most interesting. The values and their meanings are as follows. Note that HASH_AT_BEGIN and HASH_AT_END are mutually exclusive. If you set putMessage=true with a HashFilter, then be sure to specify HASH_AT_END.

  • DEFAULT_FLAGS = HASH_AT_BEGIN | PUT_RESULT
  • HASH_AT_END (0)
    • specifies the hash value will be located at the end of the message
  • HASH_AT_BEGIN (1)
    • specifies the hash value will be located at the beginning of the message
  • PUT_MESSAGE (2)
    • specifies whether the message should be forwarded to the attached transformation
  • PUT_HASH (4)
    • specifies whether the the hash should be forwarded to the attached transformation
  • PUT_RESULT (8)
    • specifies whether the result of the verification (a boolean) should be forwarded to the attached transformation
  • THROW_EXCEPTION (16)
    • specifies whether an exception should be thrown if digest verification fails

With THROW_EXCEPTION

The sample program below demonstrates a HMAC with SHA256 using filters (see pipelining). The HashVerificationFilter uses the THROW_EXCEPTION flag, which causes Crypto++ to throw an exception on verification failure.

AutoSeededRandomPool prng;

SecByteBlock key(16);   // SHA256::BLOCKSIZE will also work
prng.GenerateBlock(key, key.size());

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

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

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

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

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

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

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

Testing the try/catch block is easily accomplished by tampering with the message or the MAC:

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

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

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

StringSource ss(plain + mac, true, 
    new HashVerificationFilter(hmac, NULL, flags)
); // StringSource

Without THROW_EXCEPTION

The sample program below demonstrates verification using PUT_RESULT. When using the flag, the result is forwarded to the attached buffered transformation (attachment), which is a bool wrapped using an ArraySink.

AutoSeededRandomPool prng;

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

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

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

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

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

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

HMAC< SHA256 > hmac2(key, key.size());
    
bool result = false;
StringSource ss(plain + mac, true, 
    new HashVerificationFilter(hmac2,
        new ArraySink((byte*)&result, sizeof(result)),
        PUT_RESULT | HASH_AT_END
    ) // HashVerificationFilter
); // StringSource

if(result)
    cout << "Verified message" << endl;
else
    cerr << "Failed to verify message" << endl;

String and File Sources

The code above uses a couple of small strings, and it allows you to use StringSource ss(plain + mac, true, ...). Sometimes you want to use a large file, but loading a large file into memory is not economical. In this case you can use both a StringSource (for the digest) and a FileSource (for the file data). The code below shows you how to do it.

#include <iostream>
#include <string>

#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "sha.h"
#include "hex.h"

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    // Create a file of all 0's with:
    // dd if=/dev/zero of=./zero.dat bs=4096 count=1

    std::string digest;
    SHA256 sha256;

    // Create the digest on the file
    FileSource("zero.dat", true, new HashFilter(sha256, new StringSink(digest)));

    // Print the digest
    std::cout << "Digest: ";
    StringSource(digest, true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    // Create a verifier with DEFAULT_FLAGS
    byte result = 0;
    HashVerificationFilter verifier(sha256, new ArraySink(&result, sizeof(result)));

    // Wrap the data in sources
    StringSource ss(digest, true);
    FileSource fs("zero.dat", true);

    // Add the data to the filter. The digest is added first due to HASH_AT_BEGIN
    ss.TransferTo(verifier);
    fs.TransferTo(verifier);

    // Signal end of data. The verifier will finish calculating
    // the digest, and compare the expected and calculated digests.
    verifier.MessageEnd();

    if (result)
        std::cout << "Verified hash on file" << std::endl;
    else
        std::cout << "Failed to verify hash on file" << std::endl;

    return 0;
}

Downloads

CMAC-AES-Filter.zip - Demonstrates an AES based CMAC and verification with filters

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

SHA-File-Filter.zip - Demonstrates a SHA256 based verification of a file with filters