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.