Исключение InvalidCiphertext

Я новичок в cryptopp, пытаюсь шифровать и расшифровывать текст из файла. Я всегда получаю эту ошибку CryptoPP::InvalidCiphertext в ячейке памяти 0x0012efe4 сразу после этих строк:

CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );
stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext.c_str() ), ciphertext.length());
stfDecryptor.MessageEnd();

Код шифрования/дешифрования:

BOOL Encryption()
{
    // Key and IV setup
    byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE ];
    memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
    memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );

    HW_PROFILE_INFO hwProfileInfo;
    GetCurrentHwProfile(&hwProfileInfo);

    (hwProfileInfo.szHwProfileGuid, strlen(hwProfileInfo.szHwProfileGuid), key);     
    (hwProfileInfo.szHwProfileGuid, strlen(hwProfileInfo.szHwProfileGuid), iv);

    // String and Sink setup
    string STRING;
    ifstream infile;
    infile.open ("test2.txt");

    getline(infile,STRING, '\0'); // Saves the line in STRING.
    char cFilm[1000];
    strcpy(cFilm,STRING.c_str());
    infile.close();

    std::string plaintext = cFilm;
    std::string ciphertext;
    std::string decryptedtext;

    // Dump Plain Text
    std::cout << "Plain Text (" << plaintext.size() << " bytes)" << std::endl;
    std::cout << plaintext;
    std::cout << std::endl << std::endl;

    // Create Cipher Text
    CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
    CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( ciphertext ) );
    stfEncryptor.Put( reinterpret_cast<const unsigned char*>( plaintext.c_str() ), plaintext.length() + 1 );
    stfEncryptor.MessageEnd();

    // Dump Cipher Text
    ofstream write ("test2a.txt", ios::out | ios::binary);
    int at = ciphertext.length()+ 1;
    write.write(ciphertext.c_str(),at);
    write.close();
    ciphertext.erase();

    remove("test2.txt");
    rename("test2a.txt","c:\\test2.txt");

    return 0;
}

BOOL Decryption()
{
    // Key and IV setup
    byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE ];
    memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
    memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );

    HW_PROFILE_INFO hwProfileInfo;
    GetCurrentHwProfile(&hwProfileInfo);

    // String and Sink setup
    string STRING2;
    ifstream infile2;
    infile2.open ("test2.txt",ios::binary);

    getline(infile2,STRING2, '\0'); // Saves the line in STRING.
    char cFilm2[1000];
    strcpy(cFilm2,STRING2.c_str());
    infile2.close();

    std::string ciphertext (cFilm2);
    std::string decryptedtext;

    // Decrypt
    CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );

    CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );
    stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext.c_str() ), ciphertext.length());
    stfDecryptor.MessageEnd();

    // Dump Decrypted Text
    ofstream write ("test2a.txt", ios::out | ios::binary);
    write << decryptedtext;
    write.close();
    decryptedtext.erase();

    remove("test2.txt");
    rename("test2a.txt","test2.txt");

    return 0;
}

person TrockFOx    schedule 22.02.2013    source источник


Ответы (1)


Ваша основная проблема заключается в использовании getline с разделителем '\0' в Decryption(). Это может работать для обычного текста в Encryption(), если он не содержит нулевых символов, но зашифрованный текст, скорее всего, будет пронизан '\0's повсюду.

Похоже, вы правильно определили, что зашифрованный файл содержит двоичные данные, но вам нужно прочитать его как таковой, например. используя std::ifstream::read или std::istreambuf_iterator.

Я обновил ваш примерный код ниже:

#include "windows.h"

#include <algorithm>  // for std::copy
#include <fstream>
#include <iostream>
#include <iterator>  // for std::istreambuf_iterator
#include <string>

#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable: 4100 4127 4189 4244)
#endif
#include "cryptopp/aes.h"
#include "cryptopp/config.h"
#include "cryptopp/files.h"
#include "cryptopp/filters.h"
#include "cryptopp/modes.h"
#ifdef _MSC_VER
#  pragma warning(pop)
#endif

namespace {
const std::string original_file("original.txt");
const std::string encrypted_file("encrypted.txt");
const std::string decrypted_file("decrypted.txt");
const int key_size(CryptoPP::AES::DEFAULT_KEYLENGTH);
const int iv_size(CryptoPP::AES::BLOCKSIZE);
}

void GetKeyAndIv(byte* key, byte* iv) {
  HW_PROFILE_INFOA profile;
  GetCurrentHwProfileA(&profile);
  char* guid(profile.szHwProfileGuid);
  assert(std::char_traits<char>::length(guid) >= key_size + iv_size);
  // Assign first 'key_size' chars of GUID to 'key'
  std::copy(guid, guid + key_size, key);
  // Assign next 'iv_size' chars of GUID to 'iv'
  std::copy(guid + key_size, guid + key_size + iv_size, iv);
};

void Encrypt() {
  // Initialise the key and IV
  byte key[key_size] = {0}, iv[iv_size] = {0};
  GetKeyAndIv(key, iv);

  // Read the file contents to a string and output to cout.  Safest to read
  // contents as binary data, although non-printable characters shouldn't be
  // output to cout.
  std::ifstream infile(original_file.c_str(), std::ios::binary);
  const std::string plaintext((std::istreambuf_iterator<char>(infile)),
                               std::istreambuf_iterator<char>());
  infile.close();
  std::cout << "Plain Text (" << plaintext.size() << " bytes)\n"
            << plaintext << "\n\n";

  // Encrypt
  CryptoPP::AES::Encryption cipher(key, key_size);
  CryptoPP::CBC_Mode_ExternalCipher::Encryption encryption(cipher, iv);
  std::string cipher_text;
  CryptoPP::StreamTransformationFilter filter(encryption,
      new CryptoPP::StringSink(cipher_text));
  filter.Put(reinterpret_cast<const byte*>(plaintext.c_str()), plaintext.size());
  filter.MessageEnd();

  // Dump cipher text
  std::ofstream outfile(encrypted_file.c_str(), std::ios::binary);
  outfile.write(cipher_text.c_str(), cipher_text.size());
  outfile.close();
}

void Decrypt() {
  // Initialise the key and IV
  byte key[key_size] = {0}, iv[iv_size] = {0};
  GetKeyAndIv(key, iv);

  // Read the encrypted file contents to a string as binary data.
  std::ifstream infile(encrypted_file.c_str(), std::ios::binary);
  const std::string cipher_text((std::istreambuf_iterator<char>(infile)),
                                 std::istreambuf_iterator<char>());
  infile.close();

  // Decrypt
  CryptoPP::AES::Decryption cipher(key, key_size);
  CryptoPP::CBC_Mode_ExternalCipher::Decryption decryption(cipher, iv);
  std::string decrypted_test;
  CryptoPP::StreamTransformationFilter filter(decryption,
      new CryptoPP::StringSink(decrypted_test));
  filter.Put(reinterpret_cast<const byte*>(cipher_text.c_str()),
             cipher_text.size());
  filter.MessageEnd();

  // Dump decrypted text
  std::ofstream outfile(decrypted_file.c_str(), std::ios::binary);
  outfile.write(decrypted_test.c_str(), decrypted_test.size());
  outfile.close();
}

int main() {
  try {
    Encrypt();
    Decrypt();
  }
  catch(const CryptoPP::Exception& exception) {
    std::cout << "Caught exception: " << exception.what() << '\n';
    return -1;
  }
  return 0;
}

Еще более простой вариант — использовать классы CryptoPP FileSource и FileSink, чтобы избежать чтения/записи файлов вручную:

void Encrypt() {
  byte key[key_size] = {0}, iv[iv_size] = {0};
  GetKeyAndIv(key, iv);
  CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryption;
  encryption.SetKeyWithIV(key, key_size, iv, iv_size);
  CryptoPP::FileSource file_source(original_file.c_str(), true,
    new CryptoPP::StreamTransformationFilter(encryption,
      new CryptoPP::FileSink(encrypted_file.c_str())));
}

void Decrypt() {
  byte key[key_size] = {0}, iv[iv_size] = {0};
  GetKeyAndIv(key, iv);
  CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryption;
  decryption.SetKeyWithIV(key, key_size, iv, iv_size);
  CryptoPP::FileSource file_source(encrypted_file.c_str(), true,
    new CryptoPP::StreamTransformationFilter(decryption,
      new CryptoPP::FileSink(decrypted_file.c_str())));
}
person Fraser    schedule 23.02.2013
comment
Я должен тебе пиво! Благодарю вас! - person TrockFOx; 24.02.2013
comment
Ну, я больше люблю виски... но в крайнем случае пиво тоже подойдет! :-) Рад, что помогло. - person Fraser; 25.02.2013
comment
Вы должны пометить ответ Фрейзера как решение, чтобы другие посетители страницы знали, что он правильный. - person jww; 02.10.2013