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_RESULTHASH_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