AES/CTR 使用 Crypto++ 解密意外停止?
AES/CTR decryption stops unexpectedly using Crypto++?
我正在尝试使用 Crypto++ 库 对字节数组 (vector<unsigned char>
) 进行 AES 加密和解密。加密工作正常。
我的函数生成一个随机 IV 并将其放在加密数据的前面。解密当然是读IV。我修改了 this 答案中的代码,因此它适用于我的矢量和 CTR/No 填充。
程序在第stfDecryptor.Put(...)
行崩溃。一开始我以为数据或IV读取不正确,但检查后发现并非如此。
我希望我在这里犯了一个非常明显的错误。
谢谢大家:)
Class 来电:
//The code is not clean, i want to get it working first and then clean it up.
auto key = Helper::RandomBytes(16); //returns "byte Array" with random Bytes
auto data = Helper::UTF8String2ByteArray("HELLO WORLD!");
auto encrypted = AESCrypt::encrypt(key, data);
cout << Helper::ByteArray2HexString(key);
cout << "\r\n";
cout << Helper::ByteArray2HexString(data);
cout << "\r\n";
cout << Helper::ByteArray2HexString(encrypted);
cout << "\r\n";
auto decrypted = AESCrypt::decrypt(key, encrypted);
auto clear = Helper::ByteArray2UTF8String(decrypted);
Class:
vector<unsigned char> AESCrypt::encrypt(vector<unsigned char> key_, vector<unsigned char> data)
{
vector<unsigned char> iv_ = Helper::RandomBytes(16); //returns "byte Array" with random Bytes
byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];
for (size_t i = 0; i < AES::DEFAULT_KEYLENGTH; i++)
key[i] = key_[i];
for (size_t i = 0; i < iv_.size(); i++)
iv[i] = iv_[i];
AES::Encryption aesEncryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Encryption ctrEncryption(aesEncryption, iv);
vector<unsigned char> encrypted;
StreamTransformationFilter stfEncryptor(
ctrEncryption,
new VectorSink(encrypted),
BlockPaddingSchemeDef::NO_PADDING);
stfEncryptor.Put((const byte*)data.data(), data.size());
stfEncryptor.MessageEnd();
vector<unsigned char> output(encrypted.size() + 16);
for (size_t i = 0; i < 16; i++)
output[i] = iv[i];
for (size_t i = 0; i < encrypted.size(); i++)
output[16 + i] = encrypted[i];
return output;
}
vector<unsigned char> AESCrypt::decrypt(vector<unsigned char> key_, vector<unsigned char> data_)
{
byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];
for (size_t i = 0; i < AES::DEFAULT_KEYLENGTH; i++)
key[i] = key_[i];
for (size_t i = 0; i < 16; i++)
iv[i] = data_[i];
vector<unsigned char> data(data_.size() - 16);
for (size_t i = 0; i < data.size(); i++)
{
data[i] = data_[16 + i];
}
AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
vector<unsigned char> decrypted;
StreamTransformationFilter stfDecryptor(
ctrDecryption,
new VectorSink(decrypted),
BlockPaddingSchemeDef::NO_PADDING);
stfDecryptor.Put((const byte*)data.data(), data.size()); //this is where it crashes
stfDecryptor.MessageEnd();
return decrypted;
}
这是 CallStack 的图片:
这是它在 Crypto++ 库中停止的行:
CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation());
This is the line where it stopps inside the CryptoPP Libary:
CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation());
计数器模式(CTR)对加密和解密都使用正向变换。 "Forward transformation"表示加密。 IV/counter加密生成密钥流,然后与明文或密文进行异或运算
你应该改变这个:
AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
为此:
AES::Encryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
通知计数器模式解密使用加密器。
wiki 有一个计数器模式的例子,我们把这个问答作为外部密码例子的一部分。另请参阅 Crypto++ wiki 上的 CTR Mode。
这是复制器。
$ cat test.cxx
#include "cryptlib.h"
#include "secblock.h"
#include "filters.h"
#include "modes.h"
#include "aes.h"
#include <iostream>
#include <string>
int main (int argc, char* argv[])
{
using namespace CryptoPP;
SecByteBlock key(16), iv(16);
std::memset(key, 0xff, key.size());
std::memset( iv, 0x88, iv.size());
std::string message, encrypted, decrypted;
message = "Now is the time for all good men "
"to come to the aide of their country.";
AES::Encryption aesEncryption(key, key.size());
CTR_Mode_ExternalCipher::Encryption ctrEncryption(aesEncryption, iv);
StreamTransformationFilter stfEncryptor(
ctrEncryption, new StringSink(encrypted));
stfEncryptor.Put((const byte*)&message[0], message.size());
stfEncryptor.MessageEnd();
AES::Encryption aesDecryption(key, key.size());
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
StreamTransformationFilter stfDecryptor(
ctrDecryption, new StringSink(decrypted));
stfDecryptor.Put((const byte*)&encrypted[0], encrypted.size());
stfDecryptor.MessageEnd();
std::cout << "Message: " << message << std::endl;
std::cout << "Recovered: " << decrypted << std::endl;
return 0;
}
并且:
$ g++ -g2 -O1 test.cxx ./libcryptopp.a -o test.exe
$ ./test.exe
Message: Now is the time for all good men to come to the aide of their country.
Recovered: Now is the time for all good men to come to the aide of their country.
StreamTransformationFilter stfEncryptor(
ctrEncryption,
new VectorSink(encrypted),
BlockPaddingSchemeDef::NO_PADDING);
对于计数器模式,不需要BlockPaddingSchemeDef::NO_PADDING
。这是计数器模式的默认值。
虽然不明显,但在手册 BlockPaddingScheme
的文档中有说明:
DEFAULT_PADDING means PKCS_PADDING if cipher.MandatoryBlockSize() > 1
&& cipher.MinLastBlockSize() == 0, which holds for ECB or CBC mode.
Otherwise, NO_PADDING for modes like OFB, CFB, CTR, CBC-CTS.
我正在尝试使用 Crypto++ 库 对字节数组 (vector<unsigned char>
) 进行 AES 加密和解密。加密工作正常。
我的函数生成一个随机 IV 并将其放在加密数据的前面。解密当然是读IV。我修改了 this 答案中的代码,因此它适用于我的矢量和 CTR/No 填充。
程序在第stfDecryptor.Put(...)
行崩溃。一开始我以为数据或IV读取不正确,但检查后发现并非如此。
我希望我在这里犯了一个非常明显的错误。
谢谢大家:)
Class 来电:
//The code is not clean, i want to get it working first and then clean it up.
auto key = Helper::RandomBytes(16); //returns "byte Array" with random Bytes
auto data = Helper::UTF8String2ByteArray("HELLO WORLD!");
auto encrypted = AESCrypt::encrypt(key, data);
cout << Helper::ByteArray2HexString(key);
cout << "\r\n";
cout << Helper::ByteArray2HexString(data);
cout << "\r\n";
cout << Helper::ByteArray2HexString(encrypted);
cout << "\r\n";
auto decrypted = AESCrypt::decrypt(key, encrypted);
auto clear = Helper::ByteArray2UTF8String(decrypted);
Class:
vector<unsigned char> AESCrypt::encrypt(vector<unsigned char> key_, vector<unsigned char> data)
{
vector<unsigned char> iv_ = Helper::RandomBytes(16); //returns "byte Array" with random Bytes
byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];
for (size_t i = 0; i < AES::DEFAULT_KEYLENGTH; i++)
key[i] = key_[i];
for (size_t i = 0; i < iv_.size(); i++)
iv[i] = iv_[i];
AES::Encryption aesEncryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Encryption ctrEncryption(aesEncryption, iv);
vector<unsigned char> encrypted;
StreamTransformationFilter stfEncryptor(
ctrEncryption,
new VectorSink(encrypted),
BlockPaddingSchemeDef::NO_PADDING);
stfEncryptor.Put((const byte*)data.data(), data.size());
stfEncryptor.MessageEnd();
vector<unsigned char> output(encrypted.size() + 16);
for (size_t i = 0; i < 16; i++)
output[i] = iv[i];
for (size_t i = 0; i < encrypted.size(); i++)
output[16 + i] = encrypted[i];
return output;
}
vector<unsigned char> AESCrypt::decrypt(vector<unsigned char> key_, vector<unsigned char> data_)
{
byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];
for (size_t i = 0; i < AES::DEFAULT_KEYLENGTH; i++)
key[i] = key_[i];
for (size_t i = 0; i < 16; i++)
iv[i] = data_[i];
vector<unsigned char> data(data_.size() - 16);
for (size_t i = 0; i < data.size(); i++)
{
data[i] = data_[16 + i];
}
AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
vector<unsigned char> decrypted;
StreamTransformationFilter stfDecryptor(
ctrDecryption,
new VectorSink(decrypted),
BlockPaddingSchemeDef::NO_PADDING);
stfDecryptor.Put((const byte*)data.data(), data.size()); //this is where it crashes
stfDecryptor.MessageEnd();
return decrypted;
}
这是 CallStack 的图片:
这是它在 Crypto++ 库中停止的行:
CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation());
This is the line where it stopps inside the CryptoPP Libary:
CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation());
计数器模式(CTR)对加密和解密都使用正向变换。 "Forward transformation"表示加密。 IV/counter加密生成密钥流,然后与明文或密文进行异或运算
你应该改变这个:
AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
为此:
AES::Encryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
通知计数器模式解密使用加密器。
wiki 有一个计数器模式的例子,我们把这个问答作为外部密码例子的一部分。另请参阅 Crypto++ wiki 上的 CTR Mode。
这是复制器。
$ cat test.cxx
#include "cryptlib.h"
#include "secblock.h"
#include "filters.h"
#include "modes.h"
#include "aes.h"
#include <iostream>
#include <string>
int main (int argc, char* argv[])
{
using namespace CryptoPP;
SecByteBlock key(16), iv(16);
std::memset(key, 0xff, key.size());
std::memset( iv, 0x88, iv.size());
std::string message, encrypted, decrypted;
message = "Now is the time for all good men "
"to come to the aide of their country.";
AES::Encryption aesEncryption(key, key.size());
CTR_Mode_ExternalCipher::Encryption ctrEncryption(aesEncryption, iv);
StreamTransformationFilter stfEncryptor(
ctrEncryption, new StringSink(encrypted));
stfEncryptor.Put((const byte*)&message[0], message.size());
stfEncryptor.MessageEnd();
AES::Encryption aesDecryption(key, key.size());
CTR_Mode_ExternalCipher::Decryption ctrDecryption(aesDecryption, iv);
StreamTransformationFilter stfDecryptor(
ctrDecryption, new StringSink(decrypted));
stfDecryptor.Put((const byte*)&encrypted[0], encrypted.size());
stfDecryptor.MessageEnd();
std::cout << "Message: " << message << std::endl;
std::cout << "Recovered: " << decrypted << std::endl;
return 0;
}
并且:
$ g++ -g2 -O1 test.cxx ./libcryptopp.a -o test.exe
$ ./test.exe
Message: Now is the time for all good men to come to the aide of their country.
Recovered: Now is the time for all good men to come to the aide of their country.
StreamTransformationFilter stfEncryptor( ctrEncryption, new VectorSink(encrypted), BlockPaddingSchemeDef::NO_PADDING);
对于计数器模式,不需要BlockPaddingSchemeDef::NO_PADDING
。这是计数器模式的默认值。
虽然不明显,但在手册 BlockPaddingScheme
的文档中有说明:
DEFAULT_PADDING means PKCS_PADDING if cipher.MandatoryBlockSize() > 1 && cipher.MinLastBlockSize() == 0, which holds for ECB or CBC mode. Otherwise, NO_PADDING for modes like OFB, CFB, CTR, CBC-CTS.