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

时间:2014-10-13 17:03:21

标签: c encryption openssl aes

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

EVP_CIPHER_CTX_free(ctx);

由以下人员创建:

EVP_CIPHER_CTX_new

这是在examples

的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);

3 个答案:

答案 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 memsetcalloc感到好奇,这里有一个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来创建/释放上下文,不推荐使用它们!