Recently i tried to improve my crash handler, and write logs about when objects are being destroyed. I use singleton pattern for each global object, and have function which initialize them in correct order (crash handler is last one)
But i found strange behavior of aes encrypt, everything works fine except the situation when the app is being closed, and all destructors are being called.
void shutdown() {
dbg_println("Application shutdown");
secure_string key = "12345678901234567890123456789012";
secure_string iv = "1234567890123456";
secure_string out;
int res = secure_crypto::aes_encrypt(key, iv, "shutdown", out);
if (res != 0) {
dbg_println("Application aes_encrypt failed {}", res);
}
}
That function is called in destructor of Application – object which is created at the end – so destructor is called first
AES Encrypt code i use:
using EVP_CIPHER_CTX_free_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
int secure_crypto::aes_encrypt(const secure_string &key, const secure_string &iv, const secure_string &plainText,
secure_string &encryptedText) {
dbg_println("Encrypting {} with key {} and messageIv {}",
plainText.size() > 500 ? "..." : secure_crypto::secure_string_to_hex(plainText),
secure_crypto::secure_string_to_hex(key), secure_crypto::secure_string_to_hex(iv));
try {
/*
* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256-bit AES (i.e. a 256-bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits
*/
if (key.size() != 32 || iv.size() != 16) {
return -1;
}
const auto *keyArr = (const unsigned char *) key.c_str();
const auto *ivArr = (const unsigned char *) iv.c_str();
EVP_CIPHER_CTX_free_ptr ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
secure_vector<unsigned char> keyV(keyArr, keyArr + key.size());
secure_vector<unsigned char> ivV(ivArr, ivArr + iv.size());
dbg_println("Encrypting with key {} and iv {} and status: {}", secure_crypto::secure_string_to_hex(keyV),
secure_crypto::secure_string_to_hex(ivV), ctx.get() == nullptr ? "null" : "not null");
int rc = EVP_EncryptInit(ctx.get(), EVP_aes_256_cbc(), keyArr, ivArr);
if (rc != 1) {
#if LOG_CRYPTO_ERRORS
printf("err: %s", ERR_error_string(ERR_get_error(), NULL));
dbg_println("[crypto] Error while aes encrypting: {}", rc);
#endif
return -2;
}
// Recovered text expands upto BLOCK_SIZE
encryptedText.resize(plainText.size() + BLOCK_SIZE);
int out_len1 = (int) encryptedText.size();
rc = EVP_EncryptUpdate(ctx.get(), (unsigned char *) &encryptedText[0], &out_len1,
(const unsigned char *) &plainText[0],
(int) plainText.size());
if (rc != 1) {
return -3;
}
int out_len2 = (int) encryptedText.size() - out_len1;
rc = EVP_EncryptFinal(ctx.get(), (unsigned char *) &encryptedText[0] + out_len1, &out_len2);
if (rc != 1) {
return -4;
}
// Set cipher text size now that we know it
encryptedText.resize(out_len1 + out_len2);
return 0;
} catch (std::exception &e) {
#if LOG_CRYPTO_ERRORS
dbg_println("[crypto] Error while aes encrypting: {}", e.what());
#endif
return -99;
}
}
And the result in app:
Application shutdown
Encrypting 73687574646f776e with key 3132333435363738393031323334353637383930313233343536373839303132 and messageIv 3132
3334353637383930313233343536
Encrypting with key 3132333435363738393031323334353637383930313233343536373839303132 and iv 3132333435363738393031323334
3536 and status: not null
err: error:00000000:lib(0)::reason(0)
[crypto] Error while aes encrypting: 0
Application aes_encrypt failed -2
Any ideas what may be wrong in that code?
3