Question

I am running Crypto++ doing speed tests on encryption algorithms. I am trying to time how long it takes to encrypt, then decrypt the data(eventually with more file sizes and different algorithms). I am running into a problem where I cannot loop over the code. In the following code, I am using Blowfish, but when I get to the encryption part, it gives me the error:

HashVerificationFilter: message hash or MAC not valid

What can I do to fix this? Do I need to put it in a function? If so, how would I do that?

/**
 * g++ encryption_tests.cpp -o encryption_tests -lcryptopp -lpthread -L.
 */
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <ctime>


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

#include "cryptoplusplus/cryptlib.h"
using CryptoPP::Exception;

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

#include "cryptoplusplus/modes.h"
#include "cryptoplusplus/aes.h"

#include "cryptoplusplus/filters.h"
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::AuthenticatedEncryptionFilter;
using CryptoPP::AuthenticatedDecryptionFilter;
using namespace std;

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

#include "cryptoplusplus/blowfish.h"
using CryptoPP::Blowfish;

#include "crypto++/eax.h"
using CryptoPP::EAX;

#include "cryptoplusplus/secblock.h"
using CryptoPP::SecByteBlock;

int main( int argc, char* argv[] ) {
    // Declaring variables
    const int NUMBER_OF_RUNS = 3;
    const int NUMBER_OF_TXT_FILES = 9;
    const int NUMBER_OF_JPG_FILES = 6;
    const int NUMBER_OF_PNG_FILES = 6;
    const int NUMBER_OF_AVI_FILES = 2;

    string file_names_txt[NUMBER_OF_TXT_FILES] = { "10B.txt", "100B.txt", "1KB.txt", "10KB.txt", "100KB.txt", "1MB.txt", "5MB.txt", "10MB.txt", "20MB.txt" };
    string file_names_jpg[NUMBER_OF_JPG_FILES] = { "1KB.jpg", "10KB.jpg", "100KB.jpg", "1MB.jpg", "3MB.jpg", "5MB.jpg" };
    string file_names_png[NUMBER_OF_PNG_FILES] = { "100B.png", "500B.png","1KB.png", "10KB.png","1MB.png", "5MB.png" };
    string file_names_avi[NUMBER_OF_AVI_FILES] = { "4MB.avi", "10MB.avi" };

    int time_data [NUMBER_OF_RUNS];
    string plaintext, cipher, encoded, recovered, sample_files_path, data_file, line_contents; 
    string initial_cpp_time_data = "";
    clock_t time_start, time_stop;
    double run_time, time_difference, time_average = 0;

    // This loop will run the test NUMBER_OF_RUNS times
    for ( int i = 0 ; i < NUMBER_OF_RUNS ; i++ ) {
        time_start = clock();

    // This class seeds itself using an operating system provided RNG
    AutoSeededRandomPool prng;
    // Generate a random key
    SecByteBlock key(Blowfish::DEFAULT_KEYLENGTH);
    prng.GenerateBlock(key, key.size());
    // Generate a random initialization vector
    byte iv[Blowfish::BLOCKSIZE];
    prng.GenerateBlock(iv, sizeof(iv));
    // Set key width
    EAX< Blowfish >::Encryption e;
    e.SetKeyWithIV(key, key.size(), iv);

    // Grab the data from the file we want to run the test on
    sample_files_path = "sample_files/" + file_names_txt[8];
    ifstream initial_file_contents ( sample_files_path.c_str() );
    if (initial_file_contents.is_open()) {
        while ( getline( initial_file_contents, line_contents ) ) {
            plaintext = plaintext + line_contents;
            plaintext.push_back('\n');
            initial_file_contents.close();
        }
    } else {
        cout << "Unable to open file" << endl;
    }

    // Encrypts the plaintext
    try {
        StringSource(plaintext, true, new AuthenticatedEncryptionFilter(e, new StringSink(cipher) ) ); 
    } catch ( const CryptoPP::Exception& e ) {
        cerr << e.what() << endl;
        exit(1);
    }


        // Decrypts the test
        try {
            EAX< Blowfish >::Decryption d;
            d.SetKeyWithIV(key, key.size(), iv);
            StringSource s(cipher, true, new AuthenticatedDecryptionFilter( d, new StringSink(recovered) ) );
        } catch ( const CryptoPP::Exception& e ) {
            cerr << e.what() << endl;
            exit(1);
        }

        // Stop the clock, calculate the time difference, turn to milliseconds
        time_stop = clock();
        time_difference = time_stop - time_start;
        run_time = time_difference / ( CLOCKS_PER_SEC / 1000 );
        time_data[i] = run_time;
        cout << "time_data[" << i << "]: " << time_data[i] << " milliseconds" << endl;
    }

    //Grab the data from the old file
    ifstream initial_cpp_time_data_file ( "cpp_time_data.txt" );
    if (initial_cpp_time_data_file.is_open()) {
        while ( getline( initial_cpp_time_data_file, line_contents ) ) {
            initial_cpp_time_data = initial_cpp_time_data + line_contents;
            initial_cpp_time_data.push_back('\n');
        }
            initial_cpp_time_data_file.close();
    } else {
        initial_cpp_time_data = "";
    }

    // Created a new file
    ofstream time_data_file;
    time_data_file.open("cpp_time_data.txt");

    // Insert old data first
    time_data_file << initial_cpp_time_data << endl;

    // Show the file the test ran on and insert the new data
    time_data_file << sample_files_path << endl;
    for ( int i = 0 ; i < NUMBER_OF_RUNS ; i++ ) {
        time_data_file << "time_data[" << i << "]: " << time_data[i] << " milliseconds" << endl;
        time_average = time_average + time_data[i];
    }
    time_average = time_average / NUMBER_OF_RUNS;
    time_data_file << "The average time for this is " << time_average << " milliseconds" << endl;
    cout << "The average time for this is " << time_average << " milliseconds" << endl;
    time_data_file.close();
    cout << "Done!\n";

    return 0;
}
Was it helpful?

Solution

At each iteration of the loop, you have to call:

  • cipher.clear()
  • recovered.clear()

Otherwise, the StringSink's just keep adding to the end of a previous value. You will fail on the 2nd and subsequent iterations of your loop (the 1st should be OK).

Also, there is no Resynchronize, so you can't call e.Resynchronize(iv) to restart a cipher. You have to call e.SetKeyWithIV(key, key.size(), iv) at each iteration of your loop.

Below, I could not duplicate your reuse problem. The encryption object was reused, while the decryption object was created new for each iteration. The result of running the program:

$ ./cryptopp-test.exe
plain text: String 1
recovered text: String 1
plain text: String 2
recovered text: String 2
plain text: String 3
recovered text: String 3
plain text: String 4
recovered text: String 4
plain text: String 5
recovered text: String 5

AutoSeededRandomPool prng;

SecByteBlock key(Blowfish::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );

byte iv[ Blowfish::BLOCKSIZE ];
prng.GenerateBlock( iv, sizeof(iv) );

vector<string> vv;
vv.push_back("String 1");
vv.push_back("String 2");
vv.push_back("String 3");
vv.push_back("String 4");
vv.push_back("String 5");

string plain, cipher, recovered;

try {

    EAX< Blowfish >::Encryption e1;
    e1.SetKeyWithIV( key, key.size(), iv, sizeof(iv) );

    for(unsigned i = 0; i < vv.size(); i++)
    {
        /*********************************\
        \*********************************/

        plain = vv[i];
        cout << "plain text: " << plain << endl;

        e1.SetKeyWithIV( key, key.size(), iv, sizeof(iv) );

        cipher.clear();
        StringSource ss1(plain, true,
                         new AuthenticatedEncryptionFilter( e1,
                             new StringSink( cipher )
                         )  ); // StringSource

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

        EAX< Blowfish >::Decryption d2;
        d2.SetKeyWithIV( key, key.size(), iv, sizeof(iv) );

        recovered.clear();
        StringSource ss2(cipher, true,
                         new AuthenticatedDecryptionFilter( d2,
                             new StringSink( recovered ),
                             AuthenticatedDecryptionFilter::THROW_EXCEPTION
                         ) ); // StringSource

        cout << "recovered text: " << recovered << endl;
    }

} catch (const Exception& ex) {
    cerr << ex.what() << endl;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top