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

1

Решение

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

Похоже, что вы правильно определили, что зашифрованный файл содержит двоичные данные, но вам необходимо прочитать их как таковые, например, с помощью 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())));
}
4

Другие решения

Других решений пока нет …