密文不是块大小的倍数

时间:2018-09-08 11:49:49

标签: c++ encryption crypto++

我为一段文本编写了一个简单的AES加密程序,每当我尝试解密该文本时,都会抛出错误;

  

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

这是我的加密方法;

comment

cryptkey结构;

c_crypto::cryptkey aes_key;

c_crypto::make_keys(aes_key);

std::string testmessage = "test";

c_crypto::encrypt_buffer(testmessage, aes_key.enc_key, aes_key.enc_iv);
c_crypto::decrypt_buffer(testmessage, aes_key.enc_key, aes_key.enc_iv);

std::cout << testmessage << std::endl;

struct cryptkey { unsigned char enc_key[AES_KEY_SIZE]; unsigned char enc_iv[AES_KEY_SIZE]; }; = 16

AES_KEY_SIZE函数只是调用;

make_keys()

使用void c_crypto::random_bytes(const int &amount, unsigned char *result) { CryptoPP::AutoSeededRandomPool rng; rng.GenerateBlock(result, amount); } AES_KEY_SIZE的{​​{1}}的参数

在解密功能中

cryptkey.enc_iv

在stfDecryptor.MessageEnd()中引发错误;

如果有任何用途,这里是加密功能;

cryptkey.enc_key

编辑:

这是我的解码和编码功能:

void c_crypto::decrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
    input = base64_decode(input);

    CryptoPP::AES::Decryption aesDecryption(key, AES_KEY_SIZE);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);

    CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(input));
    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(input.c_str()), input.size());
    stfDecryptor.MessageEnd();
}

1 个答案:

答案 0 :(得分:1)

void c_crypto::encrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
    CryptoPP::AES::Encryption aesEncryption(key, AES_KEY_SIZE);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);

    CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(input));
    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(input.c_str()), input.length());
    stfEncryptor.MessageEnd();

    input = base64_encode(input);
}

不要像您一样使用相同的字符串作为源和接收器。改用单独的临时文件。

大多数(全部?)块密码可以采用16字节的块,并就地加密或解密。但是,对于字符串,as字符串会更改基础分配更改。当分配更改时,基础指针也会更改。

也许使用类似以下的内容。临时人员回避了使用字符串作为源和接收器的问题。它还提供了更好的异常安全性。如果有东西横盘整理,您的input将保持不变。

void c_crypto::encrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
    AES::Encryption aesEncryption(key, AES_KEY_SIZE);
    CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);

    std::string encrypted; encrypted.reserve(input.size()+16);
    StreamTransformationFilter stfEncryptor(cbcEncryption, new StringSink(encrypted));
    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(input.c_str()), input.length());
    stfEncryptor.MessageEnd();

    std::string encoded = base64_encode(encrypted);
    std::swap(encoded, input);
}

void c_crypto::decrypt_buffer(std::string &input, unsigned char key[AES_KEY_SIZE], unsigned char iv[AES_KEY_SIZE]) {
    std::string decoded = base64_decode(input);
    std::string decrypted; decrypted.reserve(decoded.size());

    AES::Decryption aesDecryption(key, AES_KEY_SIZE);
    CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);

    StreamTransformationFilter stfDecryptor(cbcDecryption, new StringSink(decrypted));
    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(decoded.c_str()), decoded.size());
    stfDecryptor.MessageEnd();

    std::swap(decrypted, input);
}

使用缓冲区作为输入/输出参数可以正常工作。在此示例中,指针在整个过程中不会改变:

byte buff[16] = {0};
CBC_Mode<AES>::Encryption enc(key, 16, iv);
enc.ProcessBlock(buff);

但是,您的用例有些棘手,因为密文通过input附加到字符串StringSink(input)上,这不可避免地使input增长并使通过StringSource(input, ...)将数据馈送到加密器的迭代器无效。

如果有兴趣,ProcessBlockProcessString是用于转换数据的低级成员函数。像StreamTransformationFilter这样的过滤器只会为您调用它。没有魔术或恶作剧。这只是一种处理数据的高级方法。另请参阅《 doxygen手册》中的BlockTransformation


关于填充,您使用了:

StreamTransformationFilter stfEncryptor(cbcEncryption, new StringSink(input));

实际上是哪个StreamTransformationFilter构造函数:

StreamTransformationFilter (StreamTransformation &c, BufferedTransformation *attachment=NULL, BlockPaddingScheme padding=DEFAULT_PADDING)

DEFAULT_PADDING是两件事之一。对于需要填充的模式,例如ECB和CBC,它是PKCS#7填充(PKCS_PADDING)。对于不需要需要填充的模式,例如CTR,则无需填充(NO_PADDING)。

在填充方案方面,通常应该使用默认设置。