andi99
andi99

Reputation: 119

HashVerificationFilter: message hash or MAC not valid Error on modified GCM AE code

I am referring to sample code on Crypto++ wiki at CCM Mode. I have done few modifications for testing purposes and now it is throwing:

terminate called after throwing an instance of 'HashVerificationFilter::HashVerificationFailed'
what(): HashVerificationFilter: message hash or MAC not valid
Aborted (core dumped)

I have seen 'message hash or MAC not valid' exception after decryption. But I would like to pass byte array instead of string, so I think I have to use sizeof() operator instead of size(). The code is below.

When pass key and iv, sizeof function is giving their sizes as 8 instead 16 bytes.

Is the error because of AuthenticatedDecryptionFilter::DEFAULT_FLAGS?


Here is the code:

#include <iostream>
#include <cstdio>
//#include "libcryptoWrapperGCM.h"
using std::cout;
using std::endl;
using std::cerr;

#include <string>
#include <stdint.h>
using std::string;

#include "hex.h"
using CryptoPP::HexEncoder;
using CryptoPP::HexDecoder;

#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;

#include "cryptlib.h"
using CryptoPP::BufferedTransformation;
using CryptoPP::AuthenticatedSymmetricCipher;

#include "filters.h"
using CryptoPP::Redirector;
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::AuthenticatedEncryptionFilter;
using CryptoPP::AuthenticatedDecryptionFilter;

#include "aes.h"
using CryptoPP::AES;

#include "gcm.h"
using CryptoPP::GCM;

#include "assert.h"

void GCM_Encode(byte key[], byte iv[], string pdata, string cipher, const int TAG_SIZE)
    {

        // Encrypted, with Tag
        string encoded;

        cout << "key size= " << sizeof(key) << endl;
        cout << "IV size= " << sizeof(iv) << endl;

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

        try
        {
            GCM< AES >::Encryption e;
            e.SetKeyWithIV( key, sizeof(key), iv, sizeof(iv) );

            StringSource ss1( pdata, true,
                new AuthenticatedEncryptionFilter( e,
                    new StringSink( cipher ), false, TAG_SIZE
                ) // AuthenticatedEncryptionFilter
            ); // StringSource

            cout << "Encoded value: " << cipher << endl;
        }
        catch( CryptoPP::Exception& e )
        {
            cerr << e.what() << endl;
            exit(1);
        }
    }

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

void GCM_Decode(byte key[], byte iv[], string cipher, string rpdata, const int TAG_SIZE)
    {
        try
        {
            GCM< AES >::Decryption d;
            d.SetKeyWithIV( key, sizeof(key), iv, sizeof(iv) );

            AuthenticatedDecryptionFilter df( d,
                new StringSink( rpdata ),
                AuthenticatedDecryptionFilter::DEFAULT_FLAGS, TAG_SIZE
            ); // AuthenticatedDecryptionFilter

            // The StringSource dtor will be called immediately
            //  after construction below. This will cause the
            //  destruction of objects it owns. To stop the
            //  behavior so we can get the decoding result from
            //  the DecryptionFilter, we must use a redirector
            //  or manually Put(...) into the filter without
            //  using a StringSource.
            StringSource ss2( cipher, true,
                new Redirector( df /*, PASS_EVERYTHING */ )
            ); // StringSource

            // If the object does not throw, here's the only
            //  opportunity to check the data's integrity
            if( true == df.GetLastResult() ) {
                cout << "recovered text: " << rpdata << endl;
            }
        }
        catch( CryptoPP::Exception& e )
        {
            cerr << e.what() << endl;
            exit(1);
        }

    }

int main()
{
    byte key[]= {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};
    byte iv[] = {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
    string pdata = "Authenticated Encryption";
    const int TAG_SIZE = 12;
    string rpdata, cipher;

    //void GCM_Encode(byte key[], byte iv[],  string pdata, string cipher, const int TAG_SIZE)
    GCM_Encode( key, iv, pdata, cipher, TAG_SIZE);
    cout << "======INT MAIN======" << endl;
    cout << "Encryption complete" << endl;
    cout << "cipher= " << cipher << endl; 


    //void GCM_Decode(byte key[], byte iv[], string cipher, string rpdata, const int TAG_SIZE)
    GCM_Decode( key, iv, cipher, rpdata, TAG_SIZE);
    cout << "Decryption complete" << endl;
    cout << "rpdata= " << rpdata << endl;

    return 0;
}

GDB output is,

Encryption complete
cipher= 
HashVerificationFilter: message hash or MAC not valid
[Inferior 1 (process 16632) exited with code 01]

Compilation command

g++ -g3 -O3 -fPIC GCM_Test2.cpp -o GCMTest3 -lcryptopp -pthread -lrt -lc

Include path added using,

export CPLUS_INCLUDE_PATH=/usr/local/include/cryptopp

No output on locate raise.c

Upvotes: 0

Views: 1058

Answers (1)

andi99
andi99

Reputation: 119

Problem is that both functions GCM_Encode were interpreting wrong size of key and iv.

cout << "sizeof(key)= " << sizeof(key) << endl;
cout << "sizeof(iv)= " << sizeof(iv) << endl;

is 8 and not 16. So idea is to convert it to string and get its size using .size()

std::string key1( reinterpret_cast<char const*>(key), sizeof(key) )
std::string iv1( reinterpret_cast<char const*>(iv), sizeof(iv) )

But remember to provide original byte array to SetKeyWithIV function as it does not accept string as its argument.

e.SetKeyWithIV( key, key1.size(), iv, iv1.size() )

Upvotes: 1

Related Questions