2015-03-01 4 views
-1

Я играл с AES и записать в.в. и производный ключ к файлу, так что я использую его позже для расшифровки ...AES шифрования C++ (не может расшифровать зашифрованный файл)

Следующая функция шифрует файл и сохраняет в.в. и полученный ключ в файл, он также сохраняет зашифрованный текст в отдельный файл:

void MainWindow::on_button_encrypt() try 
{ 
    using namespace std; 
    using namespace Gtk; 
    using namespace CryptoPP; 

    fstream file; 

    file.open(m_file_name + ".aes", std::ios::out | std::ios::trunc); 
    if (file.is_open()) 
    { 
     // get the plain password: 
     SecByteBlock password; 
     password_dialog get_passwd(password); 
     get_passwd.run(); 


     // generate random salt 
     const int SALT_SIZE = 32; 
     SecByteBlock salt(SALT_SIZE); 
     AutoSeededRandomPool prng; 
     prng.GenerateBlock(salt.BytePtr(), SALT_SIZE); 


     // derive a key from password and salt: 
     SecByteBlock key(AES::DEFAULT_KEYLENGTH); 
     PKCS5_PBKDF2_HMAC<SHA512> gen; 
     gen.DeriveKey(key.BytePtr(), key.size(), 1, password.BytePtr(), password.size(), salt.BytePtr(), salt.size(), 200); 


     // genereate random iv: 
     SecByteBlock iv(AES::BLOCKSIZE); 
     OS_GenerateRandomBlock(false, iv.BytePtr(), AES::BLOCKSIZE); 


     // encrypt plain text: 
     AES::Encryption enc(key.BytePtr(), AES::DEFAULT_KEYLENGTH); 
     CBC_Mode_ExternalCipher::Encryption mode(enc, iv); 

     string cipher_text; 
     StringSink* sink = new StringSink(cipher_text); 
     StreamTransformationFilter encryptor(mode, sink); 

     string plain_text = m_file_buffer->get_text(); 
     encryptor.Put(reinterpret_cast<const byte*>(plain_text.c_str()), plain_text.length() + 1); 
     encryptor.MessageEnd(); 

     // write the result: 
     file << cipher_text.c_str(); 
     file.close(); 
     file.open(m_file_name + ".key", std::ios::out | std::ios::trunc); 
     file << key << '\n' << iv; 
     file.close(); 
    } 
} 
// catch ... 

выше функция записывает в.в. и производный ключ к файлу.

0000000002F9F140

0000000002F9F4E0

Следующая функция должна прочитать файл и расшифровать его, используя * .key файл:

void MainWindow::on_button_decrypt() 
{ 
    using namespace std; 
    using namespace CryptoPP; 
    Gtk::MessageDialog info("Info"); 

    fstream file; 
    file.open("decrypted.txt", ios::out | ios::trunc); 
    if (file.is_open()) 
    { 
     // read the key: 
     fstream stream; 
     string input; 

     SecByteBlock key(AES::DEFAULT_KEYLENGTH); 
     SecByteBlock iv(AES::BLOCKSIZE); 


     stream.open("test.txt.key", std::ios::in); 

     if (stream.is_open()) 
     { 
      getline(stream, input); 
      key.Assign(reinterpret_cast<const byte*>(input.c_str()), input.size()); 
      input.clear(); 
      getline(stream, input); 
      iv.Assign(reinterpret_cast<const byte*>(input.c_str()), input.size()); 
     } 
     else 
     { 
      info.set_secondary_text("can't read key file"); 
      info.run(); 
      return; 
     } 


     // decrypt: 
     AES::Decryption dec(key, AES::DEFAULT_KEYLENGTH); 
     CBC_Mode_ExternalCipher::Decryption mode(dec, iv); 

     string plain_text; 
     StringSink* sink = new StringSink(plain_text); 
     StreamTransformationFilter decryptor(mode, sink); 

     try 
     { 
      // get encrypted text from buffer (obtained from other function): 
      string cipher_text = m_file_buffer->get_text(); 
      decryptor.Put(reinterpret_cast<const byte*>(cipher_text.c_str()), cipher_text.size()); 
      decryptor.MessageEnd(); 
      file << plain_text; 
      file.close(); 
     } 
     catch (CryptoPP::Exception& ex) 
     { 
      info.set_secondary_text(ex.what()); 
      info.run(); 
     } 
    } 
} 

CryptoPP trows исключение при дешифрования заявив это:

FileTransformationFilter: длина зашифрованного текста не кратная размеру блока.

Как никогда он ничего не бросает, если процесс дешифрования выполняется в первой функции (on_btn_encrypt()) там нет файла, поэтому, похоже, у меня проблема с чтением зашифрованного файла, но понятия не имею, как это сделать?

Это содержимое зашифрованного файла: & `OôÍoYjÜMe × Q ° Þ

открытый текст: некоторый текст

Вы видите, что я здесь отсутствует? большое спасибо!

EDIT:

вот переделки, которые решили эту проблему, как мотивационные по Qmick и Artjom:

ENCRYPTION

// encrypt the file: 
AES::Encryption enc(key.BytePtr(), AES::DEFAULT_KEYLENGTH); 
CBC_Mode_ExternalCipher::Encryption mode(enc, iv); 

string file = m_file_name + ".aes"; 
FileSink* sink = new FileSink(file.c_str()); 
StreamTransformationFilter encryptor(mode, sink); 

string plain_text = m_file_buffer->get_text(); 
encryptor.Put(reinterpret_cast<const byte*>(plain_text.c_str()), plain_text.length()); 
encryptor.MessageEnd(); 


// write the key: 
file = m_file_name + ".key"; 
FileSink* out = new FileSink(file.c_str()); 
Base64Encoder* base64_enc = new Base64Encoder; 
base64_enc->Attach(out); 
base64_enc->Put(key.BytePtr(), key.size()); 
base64_enc->MessageEnd(); 



// write the iv: 
file = m_file_name + ".iv"; 
FileSink* out2 = new FileSink(file.c_str()); 
Base64Encoder* base64_enc2 = new Base64Encoder; 
base64_enc2->Attach(out2); 
base64_enc2->Put(iv.BytePtr(), iv.size()); 
base64_enc2->MessageEnd(); 

РАСШИФРОВЫВАНИЕ:

// 
// read key 
// 
string store_key; 
StringSink* string_key_in = new StringSink(store_key); 
Base64Decoder* base64_key_dec = new Base64Decoder(string_key_in); 

string file = "test.txt.key"; 
FileSource* file_key_in = new FileSource(file.c_str(), true, base64_key_dec); 

SecByteBlock key(AES::DEFAULT_KEYLENGTH); 
key.Assign(reinterpret_cast<const byte*>(store_key.c_str()), store_key.size()); 




// 
// read iv 
// 
string store_iv; 
StringSink* string_iv_in = new StringSink(store_iv); 
Base64Decoder* base64_iv_dec = new Base64Decoder(string_iv_in); 

file = "test.txt.iv"; 
FileSource* file_iv_in = new FileSource(file.c_str(), true, base64_iv_dec); 

SecByteBlock iv(AES::BLOCKSIZE); 
iv.Assign(reinterpret_cast<const byte*>(store_iv.c_str()), store_iv.size()); 



// read ciphertext: 
string store_ciphertext; 
StringSink* ciphertext_in = new StringSink(store_ciphertext); 

file = m_file_name; 
FileSource* file_ciphertext_in = new FileSource(file.c_str(), true, ciphertext_in); 

SecByteBlock cipher_text; 
cipher_text.Assign(reinterpret_cast<const byte*>(store_ciphertext.c_str()), store_ciphertext.size()); 



// 
// decrypt: 
// 
AES::Decryption dec(key, AES::DEFAULT_KEYLENGTH); 
CBC_Mode_ExternalCipher::Decryption mode(dec, iv); 

file = "decrypted.txt"; 
FileSink* sink = new FileSink(file.c_str()); 
StreamTransformationFilter decryptor(mode, sink); 

decryptor.Put(cipher_text.BytePtr(), cipher_text.size()); 
decryptor.MessageEnd(); 
+0

Проблема заключается в том, что длина зашифрованного текста не кратная размеру блока. (Duh). Прочитайте о блочных и вспомогательных режимах – deviantfan

+0

@deviantfan, спасибо, я сделал, и, как я сказал в своем сообщении выше, такой проблемы нет, если дешифрование выполняется без чтения файла. – codekiddy

+1

Вы должны прочитать его в двоичном формате, потому что зашифрованный текст может содержать всевозможные непечатаемые и пробельные символы, такие как '\ n' и' \ 0'. –

ответ

2

Нет шифрованного текста guarentee, не будет содержать escape-последовательность, например \n, которые делают getline() ошибочной строкой (усеченной).

Поэтому рекомендуется преобразовать шифрованный текст в шестнадцатеричный или что-то еще, чтобы избежать escape-последовательности.

+0

Благодарим вас, hex ecnoding, а также прочитайте \ write в двоичном режиме, как было сказано Artjom B., решили проблему. – codekiddy

+0

Я отредактировал свой ответ для других людей в будущем, которые могут столкнуться с такой проблемой. – codekiddy

Смежные вопросы