在OpenSSL中释放/分配上下文的正确方法

Van*_*nya 16 c encryption openssl aes

我在我的程序中使用Open SSL,使用aes密码加密和解密数据.目前有一点内存泄漏,所以我正在寻找一种方法来解决这个问题.在我的加密解密例程中,我有这样的上下文

EVP_CIPHER_CTX_free(ctx);
Run Code Online (Sandbox Code Playgroud)

并创建:

EVP_CIPHER_CTX_new
Run Code Online (Sandbox Code Playgroud)

这是在示例中的OpenSSL wiki页面上

但!在MAN页面上,有使用EVP_CIPHER_CTX_cleanupEVP_CIPHER_CTX_init功能的建议.所以基本上应该正确使用的是EVP_CIPHER_CTX_new/ EVP_CIPHER_CTX_free某种方式被弃用了吗?并且EVP_CIPHER_CTX_new/ EVP_CIPHER_CTX_freeEVP_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);
Run Code Online (Sandbox Code Playgroud)

mwo*_*era 23

首先,如果您想要一个精确的答案,您应该始终指定您正在使用的OpenSSL版本.FYI 1.0.2是当前的长期支持版本,而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);
Run Code Online (Sandbox Code Playgroud)

和1.1.0手册页说:

EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
Run Code Online (Sandbox Code Playgroud)

如果你看一下1.0.2中EVP_CIPHER_CTX_init 的代码

void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
{
   memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
   /* ctx->cipher=NULL; */
}
Run Code Online (Sandbox Code Playgroud)

而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;
}
Run Code Online (Sandbox Code Playgroud)

所以你最好初始化上下文,比如在1.1.0示例中:

EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
Run Code Online (Sandbox Code Playgroud)

对于1.1.0,同样适用.

为了释放记忆:

1.0.2手册页:

EVP_CIPHER_CTX_cleanup(&ctx);
Run Code Online (Sandbox Code Playgroud)

1.1.0手册页:

EVP_CIPHER_CTX_free(ctx);
Run Code Online (Sandbox Code Playgroud)

但是,如果你检查代码,你可以看到1.0.2:

void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
{
   if (ctx) {
       EVP_CIPHER_CTX_cleanup(ctx);
      OPENSSL_free(ctx);
   }
}
Run Code Online (Sandbox Code Playgroud)

所以你应该EVP_CIPHER_CTX_free用来解除分配.如果您只想重置其他操作的上下文,则EVP_CIPHER_CTX_cleanup(1.0.2)和EVP_CIPHER_CTX_reset(1.1.0)是您的朋友.

如果你是好奇malloc memsetcalloc,这里有一个很好的解释


Maa*_*wes 5

你不应该再使用EVP_EncryptInit了.该函数确实自动创建了特定的上下文,但它不支持后来添加的加密引擎.EVP_EncryptInit_ex但是明确指出:

ctx 必须在调用此函数之前初始化.

所以EVP_CIPHER_CTX_new我想你需要在这里使用.

EVP_CIPHER_CTX_free是另一回事,它似乎已被弃用,我在OpenSSL的手册页上看不出任何提及它.使用后删除密钥材料和密码的其他状态是一种很好的做法(并且是NIST认证功能所必需的).否则,攻击者可能会扫描内存或在稍后阶段使用溢出.

名称EVP_CIPHER_CTX_free仅表示应释放CTX内存.但释放内存并不意味着它首先被清除敏感信息; 它只是返回到系统,它没有义务覆盖它.EVP_CIPHER_CTX_cleanup另一方面,在释放内存之前会明确地清除这些信息(或者它至少做了一次体面的尝试,我认为).因此,您需要在提供密钥材料后调用此函数.


Van*_*nya -5

好吧,我想现在已经清楚了。如果你这样做EVP样式加密/解密,请确保像这样创建上下文:

  EVP_CIPHER_CTX ctx;
  EVP_CIPHER_CTX_init(&ctx);
Run Code Online (Sandbox Code Playgroud)

并像这样释放它:

EVP_CIPHER_CTX_cleanup(&ctx); 
Run Code Online (Sandbox Code Playgroud)

不要使用EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free来创建/释放上下文,它们已被弃用!

  • 我的想法恰恰相反。事实上openssl-1.1.0使EVP_CIPHER_CTX成为不透明类型,因此上面的第一种形式是编译错误 (8认同)
  • 这个答案与其他答案中所述完全相反。请更新或不接受它。 (3认同)