我的 openssl 加密库有问题,即使在退出函数作用域后进行解密后,解密的字符串也不会从内存中删除。我的代码:
int crypto::aes_decrypt(const crypto::vector<unsigned char> &data, const crypto::string &key, const crypto::string &iv,
crypto::vector<unsigned char> &decrypted) {
try {
int len;
int plaintext_len;
const auto *dataArr = data.data();
size_t dataLength = data.size();
if (key.length() != 32 || iv.length() != 16) {
return -1;
}
auto *plaintext = new unsigned char[dataLength + 16];
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (ctx == nullptr) {
return -2;
}
const auto *keyArr = reinterpret_cast<const unsigned char *>(key.data());
const auto *ivArr = reinterpret_cast<const unsigned char *>(iv.data());
/*
* 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 (1 != EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyArr, ivArr, 0)) {
EVP_CIPHER_CTX_free(ctx);
return -3;
}
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary.
*/
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, dataArr, dataLength)) {
EVP_CIPHER_CTX_free(ctx);
return -4;
}
plaintext_len = len;
/*
* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) {
EVP_CIPHER_CTX_free(ctx);
return -5;
}
plaintext_len += len;
decrypted = crypto::vector<unsigned char>(plaintext, plaintext + plaintext_len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
free(plaintext);
return 0;
} catch (exception &e) {
#ifdef DEBUG_SHARED_LIBRARIES
cout << "Error while aes decrypting: " << e.what() << endl;
#endif
return -99;
}
}
void test() {
string key = "abcdefghijklmnopabcdefghijklmnop";
string iv = "1234567890123456";
string b64 = "82fgiOvXUXrnkGeRsCjKgA==";
vector<unsigned char> decrypted;
int i = crypto::aes_decrypt(crypto::base64_decode(b64), key, iv, decrypted);
if (i != 0) {
cout << "Error: " << i << endl;
return;
}
string dec = {decrypted.begin(), decrypted.end()};
// cout << "Decrypted raw: " << string_utils::char_array_to_hex(decrypted.data(), decrypted.size()) << endl;
cout << "Decrypted: " << dec << endl;
cout << "Click to clear" << endl;
string input;
getline(cin, input);
}
我尝试了很多组合,但字符串和向量仍然相同 - 解密的字符串仍在内存中
退出函数作用域之前:
退出函数作用域后:
在内存转储中:
还有另一个:
有什么建议我该如何处理吗?我认为 aes 解密实现有问题,因为在内存转储中有很多与 openssl 加密库相关的加密方法
OPENSSL_cleanse()
功能:
用一串 0 填充大小为OPENSSL_cleanse()
的ptr
。 ...len
在释放内存之前,您不能安全地使用
memset()
等函数来清除内存 - 编译器可以优化此类调用,因为根据 C 和 C++ 标准,它们对程序没有影响。 C 在可选附件 K 中确实提供了 memset_s()
功能,并且 将清除内存:
...与 memset 不同,对 memset_s 函数的任何调用都应严格按照(5.1.2.3)中描述的抽象机规则进行评估。也就是说,对 memset_s 函数的任何调用都应假设 s 和 n 指示的内存将来可以访问,因此必须包含 c 指示的值。
您还需要小心使用像
vector
这样的C++容器。您无法明确控制此类 C++ 容器使用的内存,因此无法保证它们不会在内存中的某个位置留下敏感数据的副本。
我在这里找到了我要找的东西:
https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
typedef std::basic_string<char, std::char_traits<char>, zallocator<char> > secure_string;
离开函数作用域时,
secure_string
将从内存中清除。