【问题标题】:AES encryption C++ (can't decrypt encrypted file)AES加密C++(不能解密加密文件)
【发布时间】:2015-05-01 15:54:02
【问题描述】:

我正在使用 AES 并将 iv 和派生密钥写入文件,以便稍后使用它进行解密...

以下函数加密文件并将iv和派生密钥保存到文件中,它还将加密文本保存到单独的文件中:

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 ...

上述函数将iv和派生密钥写入文件。

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 在解密时抛出异常:

FileTransformationFilter:密文长度不是块大小的倍数。

如果在第一个函数 ( on_btn_encrypt() ) 中完成解密过程,它不会抛出任何东西,在那里没有读取任何文件,所以看起来我在读取加密文件时遇到了问题,但不知道怎么做?

这是加密文件的内容: &`OôÍoYjÜMe×Q°Þ

明文是: 一些文字

你知道我在这里遗漏了什么吗?非常感谢!

编辑:

这里是解决 Qmick 和 Artjom 建议的问题的修改:

加密

// 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();

【问题讨论】:

  • 问题是ciphertext length is not multiple of a block size. (duh)。了解块模式和填充模式
  • @deviantfan,谢谢,我做到了,正如我在上面的帖子中所说,如果在不读取文件的情况下完成解密,则不会出现这样的问题。
  • 您必须以二进制形式阅读它,因为密文可以包含各种不可打印的空白字符,例如\n\0
  • 感谢 Artjom!以二进制模式读/写以及十六进制编码/解码输出解决了这个问题。

标签: c++ encryption cryptography aes


【解决方案1】:

没有保证密文不会包含\n这样的转义序列,这会使getline()得到错误的字符串(截断)。

所以建议将密文转成十六进制或其他形式,避免转义序列。

【讨论】:

  • 谢谢你,十六进制 ecnoding 以及 Artjom B 建议的二进制模式下读写。解决了这个问题。
  • 我为以后可能遇到此类问题的其他人编辑了答案。
猜你喜欢
  • 2013-04-19
  • 1970-01-01
  • 1970-01-01
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
相关资源
最近更新 更多