Как обойти Blowfish Crypto++

Я запускаю Crypto++, выполняю тесты скорости алгоритмов шифрования. Я пытаюсь рассчитать, сколько времени потребуется для шифрования, а затем расшифровать данные (в конечном итоге с большим размером файла и разными алгоритмами). Я столкнулся с проблемой, когда я не могу перебрать код. В следующем коде я использую Blowfish, но когда я добираюсь до части шифрования, возникает ошибка:

HashVerificationFilter: message hash or MAC not valid

Что я могу сделать, чтобы исправить это? Мне нужно поместить это в функцию? Если да, то как бы я это сделал?

/**
 * 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;
}

person j.atec    schedule 25.04.2014    source источник
comment
В вашем коде отсутствует цикл, о котором вы говорите. Кроме того, если бы вы могли сократить тестовый пример до чего-то простого со строками (а не с файлами), это помогло бы людям протестировать ваш код (я пытаюсь запустить предложенный код).   -  person jww    schedule 27.04.2014


Ответы (1)


На каждой итерации цикла вы должны вызывать:

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

В противном случае StringSink просто продолжают добавляться к концу предыдущего значения. Вы потерпите неудачу на 2-й и последующих итерациях вашего цикла (1-й должен быть в порядке).

Кроме того, нет Resynchronize, поэтому вы не можете вызвать e.Resynchronize(iv) для перезапуска шифра. Вы должны вызывать e.SetKeyWithIV(key, key.size(), iv) на каждой итерации вашего цикла.

Ниже я не смог воспроизвести вашу проблему повторного использования. Объект шифрования использовался повторно, а объект дешифрования создавался новым для каждой итерации. Результат работы программы:

$ ./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;
}
person jww    schedule 25.04.2014