Streamtransformationfilter: Invalid Pkcs #7 Block Padding Found (Crypto++)
I Am Trying to Decrypt Ciphertext Provided by a User Using a Qt Qlineedit. If I Encrypt the String and Then Decrypt It Using the Code Below, Everything Works...
I am trying to decrypt ciphertext provided by a user using a Qt QLineEdit.
If I encrypt the string and then decrypt it using the code below, everything works as expected.
crypto::aes_pbkdf2_decrypt(crypto::aes_pbkdf2_encrypt("ciphertxt", "keystr"), "keystr");
When the string is encrypted, it gets an output to a QtLineEdit. When I attempt to decrypt that ciphertext output, it throws StreamTransformationFilter: invalid PKCS #7 block padding found.
This doesn't make much sense to me since it works perfectly when I directly decrypt the output from the encryption function as shows above.
Here are the functions I am using for encryption/decryption:
Encrypt
std::string crypto::aes_pbkdf2_encrypt(std::string pPlainText, std::string pKey)
{
CryptoPP::AutoSeededRandomPool prng;
CryptoPP::SecByteBlock iv (CryptoPP::AES::BLOCKSIZE);
CryptoPP::SecByteBlock salt (CryptoPP::AES::DEFAULT_KEYLENGTH / 2);
CryptoPP::SecByteBlock key (CryptoPP::AES::DEFAULT_KEYLENGTH);
std::string cipher, output, cipher_str, iv_str, salt_str;
prng.GenerateBlock(salt, salt.size());
prng.GenerateBlock(iv, iv.size());
key = pbkdf2_salt_hash(pKey, salt);
try {
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
encrypt.SetKeyWithIV(key, key.size(), iv);
CryptoPP::StringSource stringsource(pPlainText, true,
new CryptoPP::StreamTransformationFilter(encrypt,
new CryptoPP::StringSink(cipher)
)
);
} catch (const CryptoPP::Exception& e) {
std::cerr << e.what() << std::endl;
return "";
}
CryptoPP::HexEncoder encoder (new CryptoPP::FileSink(std::cout));
encoder.Detach(new CryptoPP::StringSink(salt_str));
encoder.Put(salt, salt.size());
encoder.MessageEnd();
encoder.Detach(new CryptoPP::StringSink(iv_str));
encoder.Put(iv, iv.size());
encoder.MessageEnd();
encoder.Detach(new CryptoPP::StringSink(cipher_str));
encoder.Put((const CryptoPP::byte*) &cipher[0], cipher.size());
encoder.MessageEnd();
output = iv_str + cipher_str + salt_str;
std::cout << "Cipher: " << output << std::endl;
return output;
}
Decrypt
std::string crypto::aes_pbkdf2_decrypt(std::string pCipherText, std::string pKey)
{
std::string iv_str = pCipherText.substr(0, 32);
std::string salt_str = pCipherText.substr(pCipherText.size() - 16, pCipherText.size());
std::string cipher_str = pCipherText.substr(iv_str.size(), pCipherText.size() - (iv_str.size() + salt_str.size()));
std::string iv, salt, cipher, output;
CryptoPP::HexDecoder decoder(new CryptoPP::FileSink(std::cout));
decoder.Attach(new CryptoPP::StringSink(iv));
decoder.Put((CryptoPP::byte*) iv_str.data(), iv_str.size());
decoder.MessageEnd();
decoder.Attach(new CryptoPP::StringSink(salt));
decoder.Put((CryptoPP::byte*) salt_str.data(), salt_str.size());
decoder.MessageEnd();
decoder.Attach(new CryptoPP::StringSink(cipher));
decoder.Put((CryptoPP::byte*) cipher_str.data(), cipher_str.size());
decoder.MessageEnd();
try {
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor;
CryptoPP::SecByteBlock salt_blk ((CryptoPP::byte*) salt.data(), salt.size());
CryptoPP::SecByteBlock iv_blk ((CryptoPP::byte*) iv.data(), iv.size());
CryptoPP::SecByteBlock key = pbkdf2_salt_hash(pKey, salt_blk);
decryptor.SetKeyWithIV(key.data(), key.size(), iv_blk);
CryptoPP::StringSource stringsource (cipher, true,
new CryptoPP::StreamTransformationFilter(decryptor,
new CryptoPP::StringSink(output)
)
);
} catch (const CryptoPP::Exception& e) {
std::cerr << e.what() << std::endl;
return "";
}
return output;
}
PBKDF2 Hashing
CryptoPP::SecByteBlock crypto::pbkdf2_salt_hash(std::string pPlainText, CryptoPP::SecByteBlock pSalt)
{
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256> pbkdf;
CryptoPP::SecByteBlock output(CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::byte text_bytes[pPlainText.size()];
std::memcpy(text_bytes, pPlainText.data(), pPlainText.size());
size_t plaintext_length = strlen((const char*)text_bytes);
size_t salt_length = pSalt.size();
pbkdf.DeriveKey(output, output.size(), 0, text_bytes, plaintext_length, pSalt, salt_length, 1024, 0.0f);
return output;
}
What I have already tried:
I tried each padding type in CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme to CryptoPP::StringSink in the decryption function. Only creates odd 'OpenType' errors and strangely formatted outputs.