Reputation: 135
I'm trying to decrypt
a string that has been encrypted using openssl
, evp_aes_128_cbc
, and a password/salt
I have succeeded decrypting
it using openssl
, but not using the crypto++ lib.
The key
generated on the crypto++
matches the openssl
key
but the iv's
doesnt.
The code result in an exception in the line stf.MessageEnd();
its breaks in the crypto++
file filter.cpp
at:
if (length != s)
throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");
where length is 24
and s
is 16
...
c++/openssl
encryption function:
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
std::string stringToBase64(const std::string& input)
{
BIO* bio = BIO_new(BIO_s_mem());
BIO* base64 = BIO_new(BIO_f_base64());
BIO_set_flags(base64, BIO_FLAGS_BASE64_NO_NL); // No line breaks
BIO* bio_chain = BIO_push(base64, bio);
BIO_write(bio_chain, input.c_str(), input.length());
BIO_flush(bio_chain);
char* encoded_data;
long encoded_length = BIO_get_mem_data(bio, &encoded_data);
std::string base64_string(encoded_data, static_cast<size_t>(encoded_length));
// Free the BIOs
BIO_free_all(bio_chain);
return base64_string;
}
std::string encrypt(std::string str, const char* password, const char* salt)
{
unsigned char key[EVP_MAX_KEY_LENGTH];
unsigned char derived[32]; // 32 bytes for both key and IV
if(!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(password), strlen(password),
reinterpret_cast<const unsigned char *>(salt), strlen(salt),
1000, EVP_sha1(), 32, derived)) // Derive 32 bytes
{
EVP_CIPHER_CTX_free(ctx);
return std::string();
}
unsigned char key[EVP_MAX_KEY_LENGTH];
unsigned char iv[EVP_MAX_IV_LENGTH];
// Use the first 16 bytes as the key
memcpy(key, derived, 16);
// Use the remaining 16 bytes as the IV
memcpy(iv, derived + 16, 16);
if (EVP_CipherInit(ctx, EVP_aes_128_cbc(), key, iv, true) != 1)
{
EVP_CIPHER_CTX_free(ctx);
return std::string();
}
const int MAX_BUFFER_SIZE = str.size();
int len = 0;
int outLen;
int blocksize = EVP_CIPHER_CTX_block_size(ctx);
std::string cipherBuf;
cipherBuf.resize(MAX_BUFFER_SIZE + blocksize);
if (EVP_CipherUpdate(ctx, reinterpret_cast<uchar *>(cipherBuf.data()), &outLen, reinterpret_cast<uchar *>(str.data()), str.size()) != 1)
{
EVP_CIPHER_CTX_free(ctx);
return std::string();
}
len += outLen;
if (EVP_CipherFinal(ctx, reinterpret_cast<uchar *> (cipherBuf.data() + len), &outLen) != 1)
{
EVP_CIPHER_CTX_free(ctx);
return std::string();
}
len += outLen;
cipherBuf.resize(len);
EVP_CIPHER_CTX_free(ctx); // Cleanup
str = stringToBase64(cipherBuf);
memset(cipherBuf.data(), 0, MAX_BUFFER_SIZE + blocksize); // Clear cipherBuf
return str;
}
int main(int argc, char* argv[])
{
const char* password = "password123";
const char* salt = "salt123";
std::string enc = ecrypt("test123", password, salt);
size_t saltLen = strlen(salt);
std::string derived_key(16 + saltLen, '\0'); // AES-128
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf;
pbkdf.DeriveKey(reinterpret_cast<byte*>(&derived_key[0]), derived_key.size(), 0,
reinterpret_cast<const byte*>(password),
strLen(password),
reinterpret_cast<const byte*>(salt),
saltLen, 1000); // '1000' same as on the openssl function
CryptoPP::SecByteBlock key(16), iv(saltLen);
std::memcpy(key.data(), derived_key.data(), key.size());
std::memcpy(iv.data(), derived_key.data() + saltLen, iv.size());
CryptoPP::HexEncoder encoder;
std::string key_hex, iv_hex;
encoder.Attach(new CryptoPP::StringSink(key_hex));
encoder.Put(key.data(), key.size());
encoder.MessageEnd();
encoder.Attach(new CryptoPP::StringSink(iv_hex));
encoder.Put(iv.data(), iv.size());
encoder.MessageEnd();
std::cout << "Key: " << key_hex;
std::cout << "IV: " << iv_hex;
CryptoPP::AES::Decryption aesDecryption(key, key.size());
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);
std::string dec;
CryptoPP::StreamTransformationFilter stf(cbcDecryption, new CryptoPP::StringSink(dec));
stf.Put(reinterpret_cast<const unsigned char*>(enc.data()), enc.size());
stf.MessageEnd();
}
Upvotes: 0
Views: 132