我在程序中使用Open SSL,使用aes密码加密和解密数据。目前有一点内存泄漏,所以我正在寻找一种方法来解决这个问题。在我的加密解密例程中,我有像上面这样的上下文
EVP_CIPHER_CTX_free(ctx);
由以下人员创建:
EVP_CIPHER_CTX_new
这是在examples
的OpenSSL wiki页面上但是!在MAN页面上,建议使用EVP_CIPHER_CTX_cleanup
和EVP_CIPHER_CTX_init
函数。所以基本上应该正确使用的是EVP_CIPHER_CTX_new
/ EVP_CIPHER_CTX_free
是否已被弃用? EVP_CIPHER_CTX_new
/ EVP_CIPHER_CTX_free
和EVP_CIPHER_CTX_init
/ EVP_CIPHER_CTX_cleanup
之间有什么重大差异吗?
if(!(ctx = EVP_CIPHER_CTX_new())) return -1;
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
{
EVP_CIPHER_CTX_free(ctx);
return -1;
}
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
{
EVP_CIPHER_CTX_free(ctx);
return -1;
}
ciphertext_len = len;
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { EVP_CIPHER_CTX_free(ctx); return -1; }
ciphertext_len += len;
EVP_CIPHER_CTX_free(ctx);
答案 0 :(得分:16)
首先,如果您想要一个精确的答案,您应该始终指定您正在使用的OpenSSL版本。 FYI 1.0.2是当前Long Term Support版本,而1.1.0是最新版本(2016年9月)。
如果您阅读1.1.0手册页,您会注意到:
EVP_CIPHER_CTX在OpenSSL 1.1.0中变得不透明。结果是, 出现了EVP_CIPHER_CTX_reset()和EVP_CIPHER_CTX_cleanup() 消失了。 EVP_CIPHER_CTX_init()仍然是别名 EVP_CIPHER_CTX_reset()。
简短回答是:您应该使用EVP_CIPHER_CTX_new
初始化并EVP_CIPHER_CTX_free
释放内存,无论版本如何,这都是原因。
<强>分配强>
1.0.2手册页说:
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
和1.1.0手册页说:
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
如果你看一下1.0.2中EVP_CIPHER_CTX_init的code
void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
{
memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
/* ctx->cipher=NULL; */
}
而EVP_CIPHER_CTX_new是:
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
{
EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof *ctx);
if (ctx)
EVP_CIPHER_CTX_init(ctx);
return ctx;
}
所以你最好初始化上下文,比如1.1.0例子:
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
对于1.1.0,同样适用。
释放记忆:
1.0.2手册页:
EVP_CIPHER_CTX_cleanup(&ctx);
1.1.0手册页:
EVP_CIPHER_CTX_free(ctx);
但如果你检查code,你可以看到1.0.2:
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
{
if (ctx) {
EVP_CIPHER_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
}
所以你应该使用EVP_CIPHER_CTX_free
来解除分配。
如果您只想重置其他操作的上下文,那么EVP_CIPHER_CTX_cleanup
(1.0.2)和EVP_CIPHER_CTX_reset
(1.1.0)就是您的朋友。
如果您对malloc
memset
和calloc
感到好奇,这里有一个good explanation
答案 1 :(得分:5)
您不应再使用EVP_EncryptInit
了。该函数确实自动创建了特定的上下文,但它不支持后来添加的加密引擎。 EVP_EncryptInit_ex
明确指出:
在调用此函数之前必须初始化
ctx
。
因此我想在这里使用EVP_CIPHER_CTX_new
。
EVP_CIPHER_CTX_free
是另一回事,它似乎已被弃用,我在OpenSSL的手册页上没有看到它。使用后删除密钥材料和密码的其他状态是良好的做法(并且
EVP_CIPHER_CTX_free
的名称仅表示应释放CTX内存。但释放内存并不意味着它首先被清除敏感信息;它只是返回到系统,它没有义务覆盖它。另一方面,EVP_CIPHER_CTX_cleanup
确实在释放内存之前明确地清除了这些信息(或者它至少做了一次体面的尝试,我猜想)。因此,您需要在提供密钥材料后调用此函数。
答案 2 :(得分:0)
EVP
样式加密/解密,请确保创建上下文:
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
然后像这样释放它:
EVP_CIPHER_CTX_cleanup(&ctx);
不要使用EVP_CIPHER_CTX_new
/ EVP_CIPHER_CTX_free
来创建/释放上下文,不推荐使用它们!