从加密项目向量中解密任意选择的元素会导致无效的 PKCS #7 块错误
Decryption of an arbitrary chosen element from a vector of encrypted items causes invalid PKCS #7 block error
我正在尝试使用 Crypto++ 中的 AES 加密一些顺序数据。但是,我注意到随机选择一个加密项目并解密它会导致 StreamTransformationFilter: invalid PKCS #7 block padding found
导致相同问题的简单代码如下:
AESUtil aes;
std::vector<std::string> t = std::vector<std::string>();
for (int i = 0; i < 100; ++i) {
std::string p = "a";
auto c = aes.encrypt(p);
t.push_back(c);
}
auto d = aes.decrypt(t[78]);
其中 AESUtil 如下:
AESUtil::AESUtil() {
this->key = CryptoPP::SecByteBlock(0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
rnd.GenerateBlock(key, key.size());
// Generate a random IV
this->iv = CryptoPP::SecByteBlock(CryptoPP::AES::BLOCKSIZE);
rnd.GenerateBlock(iv, iv.size());
this->aesEncryption = CryptoPP::AES::Encryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
this->cbcEncryption = CryptoPP::CBC_Mode_ExternalCipher::Encryption(aesEncryption, iv);
this->aesDecryption = CryptoPP::AES::Decryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
this->cbcDecryption = CryptoPP::CBC_Mode_ExternalCipher::Decryption(aesDecryption, iv);
}
void AESUtil::encrypt(std::string &ciphertext, std::string &plaintext) {
CryptoPP::StreamTransformationFilter stfEncryptor(this->cbcEncryption, new CryptoPP::StringSink(ciphertext));
stfEncryptor.Put(reinterpret_cast<const unsigned char *>( plaintext.c_str()), plaintext.size());
stfEncryptor.MessageEnd();
}
void AESUtil::decrypt(std::string &plaintext, std::string &ciphertext) {
CryptoPP::StreamTransformationFilter stfDecryptor(this->cbcDecryption, new CryptoPP::StringSink(plaintext));
stfDecryptor.Put(reinterpret_cast<const unsigned char *>( ciphertext.c_str()), ciphertext.size());
stfDecryptor.MessageEnd();
}
std::string AESUtil::encrypt(std::string plaintext) {
std::string ciphertext;
//ciphertext.reserve(plaintext.size()+16);
encrypt(ciphertext, plaintext);
return ciphertext;
}
std::string AESUtil::decrypt(std::string ciphertext) {
std::string plaintext;
//plaintext.reserve(ciphertext.size()+16);
decrypt(plaintext, ciphertext);
return plaintext;
}
我认为问题与字符串中的 \0 空终止字符有关,所以我将代码更改为使用十六进制(不确定它是否正确)。但是,问题仍然存在。
void AESUtil::encrypt(std::string &ciphertext, std::string &plaintext) {
CryptoPP::ByteQueue encrypted;
CryptoPP::StreamTransformationFilter f1(this->cbcEncryption, new CryptoPP::Redirector(encrypted));
//f1.PutWord32((uint32_t)v1.size(), BIG_ENDIAN_ORDER);
f1.Put((const unsigned char *) plaintext.c_str(), plaintext.size());
f1.MessageEnd();
CryptoPP::HexEncoder encoder(new CryptoPP::StringSink(ciphertext));
encrypted.CopyTo(encoder);
encoder.MessageEnd();
}
void AESUtil::decrypt(std::string &plaintext, std::string &ciphertext) {
CryptoPP::ByteQueue decrypted;
CryptoPP::HexDecoder decoder(new CryptoPP::Redirector(decrypted));
decoder.Put(reinterpret_cast<const unsigned char *>( ciphertext.data()), ciphertext.size());
decoder.MessageEnd();
CryptoPP::StreamTransformationFilter f2(this->cbcDecryption, new CryptoPP::StringSink(plaintext));
decrypted.CopyTo(f2);
f2.MessageEnd();
}
使用以下代码,两个 AESUtil 版本都可以正常工作:
for (int i = 0; i < 100; ++i) {
std::string p = "a";
auto c = aes.encrypt(p);
auto d = aes.decrypt(c);
}
知道问题是什么以及如何解决吗?如有任何帮助,我们将不胜感激
我找到问题了。
即使 MessageEnd
被调用,IV 也在改变,保持对 AESUtil 的状态 的引用。
我通过在加密过程中随机生成IV并将其与密文存储在一起解决了这个问题。
如果有人感兴趣,这里是新代码:
void AESUtil::encrypt(std::string &ciphertext, std::string &plaintext) {
// Generate a random IV
CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE);
this->rnd.GenerateBlock(iv, iv.size());
//memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
CryptoPP::StringSink stringSink(ciphertext);
CryptoPP::ArraySource as(iv, iv.size(), true,
new CryptoPP::Redirector(stringSink));
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(this->aesEncryption, iv);
CryptoPP::ByteQueue encrypted;
CryptoPP::StreamTransformationFilter f1(cbcEncryption, new CryptoPP::Redirector(encrypted));
f1.Put(reinterpret_cast<const unsigned char *>(plaintext.c_str()), plaintext.size());
f1.MessageEnd();
CryptoPP::HexEncoder encoder(new CryptoPP::Redirector(stringSink));
encrypted.CopyTo(encoder);
encoder.MessageEnd();
std::string recovered;
CryptoPP::StringSink sink(recovered);
encrypted.CopyTo(sink);
}
void AESUtil::decrypt(std::string &plaintext, std::string &ciphertext) {
CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE);
CryptoPP::StringSource ss(ciphertext, false /* DO NOT Pump All */);
// Attach new filter
CryptoPP::ArraySink as(iv, iv.size());
ss.Attach(new CryptoPP::Redirector(as));
ss.Pump(CryptoPP::AES::BLOCKSIZE); // Pump first 16 bytes
CryptoPP::StringSink stringSink(plaintext);
CryptoPP::ByteQueue decrypted;
CryptoPP::HexDecoder decoder(new CryptoPP::Redirector(decrypted));
ss.Detach(new CryptoPP::Redirector(decoder));
ss.PumpAll();
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(this->aesDecryption, iv);
CryptoPP::StreamTransformationFilter f2(cbcDecryption, new CryptoPP::Redirector(stringSink));
decrypted.CopyTo(f2);
f2.MessageEnd();
}
我正在尝试使用 Crypto++ 中的 AES 加密一些顺序数据。但是,我注意到随机选择一个加密项目并解密它会导致 StreamTransformationFilter: invalid PKCS #7 block padding found
导致相同问题的简单代码如下:
AESUtil aes;
std::vector<std::string> t = std::vector<std::string>();
for (int i = 0; i < 100; ++i) {
std::string p = "a";
auto c = aes.encrypt(p);
t.push_back(c);
}
auto d = aes.decrypt(t[78]);
其中 AESUtil 如下:
AESUtil::AESUtil() {
this->key = CryptoPP::SecByteBlock(0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
rnd.GenerateBlock(key, key.size());
// Generate a random IV
this->iv = CryptoPP::SecByteBlock(CryptoPP::AES::BLOCKSIZE);
rnd.GenerateBlock(iv, iv.size());
this->aesEncryption = CryptoPP::AES::Encryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
this->cbcEncryption = CryptoPP::CBC_Mode_ExternalCipher::Encryption(aesEncryption, iv);
this->aesDecryption = CryptoPP::AES::Decryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
this->cbcDecryption = CryptoPP::CBC_Mode_ExternalCipher::Decryption(aesDecryption, iv);
}
void AESUtil::encrypt(std::string &ciphertext, std::string &plaintext) {
CryptoPP::StreamTransformationFilter stfEncryptor(this->cbcEncryption, new CryptoPP::StringSink(ciphertext));
stfEncryptor.Put(reinterpret_cast<const unsigned char *>( plaintext.c_str()), plaintext.size());
stfEncryptor.MessageEnd();
}
void AESUtil::decrypt(std::string &plaintext, std::string &ciphertext) {
CryptoPP::StreamTransformationFilter stfDecryptor(this->cbcDecryption, new CryptoPP::StringSink(plaintext));
stfDecryptor.Put(reinterpret_cast<const unsigned char *>( ciphertext.c_str()), ciphertext.size());
stfDecryptor.MessageEnd();
}
std::string AESUtil::encrypt(std::string plaintext) {
std::string ciphertext;
//ciphertext.reserve(plaintext.size()+16);
encrypt(ciphertext, plaintext);
return ciphertext;
}
std::string AESUtil::decrypt(std::string ciphertext) {
std::string plaintext;
//plaintext.reserve(ciphertext.size()+16);
decrypt(plaintext, ciphertext);
return plaintext;
}
我认为问题与字符串中的 \0 空终止字符有关,所以我将代码更改为使用十六进制(不确定它是否正确)。但是,问题仍然存在。
void AESUtil::encrypt(std::string &ciphertext, std::string &plaintext) {
CryptoPP::ByteQueue encrypted;
CryptoPP::StreamTransformationFilter f1(this->cbcEncryption, new CryptoPP::Redirector(encrypted));
//f1.PutWord32((uint32_t)v1.size(), BIG_ENDIAN_ORDER);
f1.Put((const unsigned char *) plaintext.c_str(), plaintext.size());
f1.MessageEnd();
CryptoPP::HexEncoder encoder(new CryptoPP::StringSink(ciphertext));
encrypted.CopyTo(encoder);
encoder.MessageEnd();
}
void AESUtil::decrypt(std::string &plaintext, std::string &ciphertext) {
CryptoPP::ByteQueue decrypted;
CryptoPP::HexDecoder decoder(new CryptoPP::Redirector(decrypted));
decoder.Put(reinterpret_cast<const unsigned char *>( ciphertext.data()), ciphertext.size());
decoder.MessageEnd();
CryptoPP::StreamTransformationFilter f2(this->cbcDecryption, new CryptoPP::StringSink(plaintext));
decrypted.CopyTo(f2);
f2.MessageEnd();
}
使用以下代码,两个 AESUtil 版本都可以正常工作:
for (int i = 0; i < 100; ++i) {
std::string p = "a";
auto c = aes.encrypt(p);
auto d = aes.decrypt(c);
}
知道问题是什么以及如何解决吗?如有任何帮助,我们将不胜感激
我找到问题了。
即使 MessageEnd
被调用,IV 也在改变,保持对 AESUtil 的状态 的引用。
我通过在加密过程中随机生成IV并将其与密文存储在一起解决了这个问题。
如果有人感兴趣,这里是新代码:
void AESUtil::encrypt(std::string &ciphertext, std::string &plaintext) {
// Generate a random IV
CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE);
this->rnd.GenerateBlock(iv, iv.size());
//memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
CryptoPP::StringSink stringSink(ciphertext);
CryptoPP::ArraySource as(iv, iv.size(), true,
new CryptoPP::Redirector(stringSink));
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(this->aesEncryption, iv);
CryptoPP::ByteQueue encrypted;
CryptoPP::StreamTransformationFilter f1(cbcEncryption, new CryptoPP::Redirector(encrypted));
f1.Put(reinterpret_cast<const unsigned char *>(plaintext.c_str()), plaintext.size());
f1.MessageEnd();
CryptoPP::HexEncoder encoder(new CryptoPP::Redirector(stringSink));
encrypted.CopyTo(encoder);
encoder.MessageEnd();
std::string recovered;
CryptoPP::StringSink sink(recovered);
encrypted.CopyTo(sink);
}
void AESUtil::decrypt(std::string &plaintext, std::string &ciphertext) {
CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE);
CryptoPP::StringSource ss(ciphertext, false /* DO NOT Pump All */);
// Attach new filter
CryptoPP::ArraySink as(iv, iv.size());
ss.Attach(new CryptoPP::Redirector(as));
ss.Pump(CryptoPP::AES::BLOCKSIZE); // Pump first 16 bytes
CryptoPP::StringSink stringSink(plaintext);
CryptoPP::ByteQueue decrypted;
CryptoPP::HexDecoder decoder(new CryptoPP::Redirector(decrypted));
ss.Detach(new CryptoPP::Redirector(decoder));
ss.PumpAll();
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(this->aesDecryption, iv);
CryptoPP::StreamTransformationFilter f2(cbcDecryption, new CryptoPP::Redirector(stringSink));
decrypted.CopyTo(f2);
f2.MessageEnd();
}