我需要多个EVP_CIPHER_CTX结构吗?

时间:2014-06-22 07:49:04

标签: aes openssl

我有一个单线程客户端/服务器应用程序,需要对其网络通信进行加密和解密。我计划使用OpenSSL的EVP API和AES-256-CBC。

我从一些例子中找到了一些示例伪代码:

// key is 256 bits (32 bytes) when using EVP_aes_256_*()
// I think iv is the same size as the block size, 128 bits (16 bytes)...is it?
1: EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
2: EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv, 1); //0=decrypt, 1=encrypt
3: EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen);
4: EVP_CipherFinal_ex(ctx, outbuf + outlen, &tmplen));
5: outlen += tmplen;
6: EVP_CIPHER_CTX_cleanup(ctx);
7: EVP_CIPHER_CTX_free(ctx);

问题来自所有这些例子,我不确定在每次加密/解密时需要做什么,以及我应该只在启动时做一次。

具体做法是:

  • 在第1行,我是否只创建一次EVP_CIPHER_CTX并继续重复使用它,直到应用程序结束?
  • 同样在第1行,我可以重复使用相同的EVP_CIPHER_CTX加密和解密,还是我应该创建其中的2个?
  • 在第2行,是否应该在我正在加密的每个数据包中重新设置IV?或者我只将IV设置一次,然后让它永远继续下去?
  • 如果我正在加密UDP数据包,数据包很容易丢失或被无序接收怎么办?我认为CBC无法正常工作,或者我需要在开始时重置IV我发出的每个数据包?

3 个答案:

答案 0 :(得分:10)

很抱歉恢复旧线程,但我注意到接受的答案中出现以下错误:

  
    

在第1行,我是否只创建一次EVP_CIPHER_CTX并继续重复使用它直到应用程序结束?

  
     

每次使用都会创建一次。也就是说,当您需要加密时,您使用相同的上下文。如果需要加密第二个流,则可以使用第二个上下文。如果您需要解密第三个流,您将使用第三个上下文。

     
    

同样在第1行,我是否可以重复使用相同的EVP_CIPHER_CTX加密和解密,或者我应该创建其中的2个?

  
     

不,见上文。

这不是必需的。从OpenSSL的手册页:

  

新代码应该使用EVP_EncryptInit_ex(),EVP_EncryptFinal_ex(),EVP_DecryptInit_ex(),EVP_DecryptFinal_ex(),         EVP_CipherInit_ex()和EVP_CipherFinal_ex()因为它们可以重用现有的上下文而无需在每次调用时分配和释放它。

换句话说,您需要在每次使用之前重新初始化上下文,但是您可以反复使用相同的上下文而无需创建(分配)新的上下文。

答案 1 :(得分:8)

  

我有一个单线程客户端/服务器应用程序,需要对其网络通信进行加密和解密。我计划使用OpenSSL的EVP API和AES-256-CBC。

如果您使用SSL_*中的libssl功能,则可能永远不会触及EVP_* API。


  

在第1行,我是否只创建一次EVP_CIPHER_CTX并继续重复使用它直到应用程序结束?

每次使用都会创建一次。也就是说,当您需要加密时,您使用相同的上下文。如果需要加密第二个流,则可以使用第二个上下文。如果您需要解密第三个流,您将使用第三个上下文。


  

同样在第1行,我是否可以重复使用相同的EVP_CIPHER_CTX加密和解密,或者我应该创建其中的2个?

不,见上文。

密码将具有不同的状态。


  

在第2行,是否应该在每个加密的数据包中重新设置IV?或者我只将IV设置一次,然后让它永远继续下去?

没有。你设置IV一次然后忘记它。上下文对象为密码管理的状态的一部分。


  

如果我加密UDP数据包,数据包很容易丢失或无序接收,该怎么办?我认为CBC无法正常工作......

如果您使用的是UDP,则由您来检测这些问题。你可能最终会重新发明TCP。

仅靠加密通常是不够的。您还需要确保真实性和完整性。您不会操作不真实的数据。这就是让SST / TLS和SSH陷入困境的原因。

例如,在SSL / TLS使用的Authenticate-Then-Encrypt(EtA)方案中,编写seminal paper on authenticated encryption关于IPSec,SSL / TLS和SSH的人称重: Last Call: (Encrypt-then-MAC for TLS and DTLS) to Proposed Standard

  

我2001年论文中的技术成果是正确但结论   关于SSL / TLS是错误的。我认为TLS正在使用新的IV和   MAC是在编码的明文上计算的,即   在TLS进行Mac-Encode-Encrypt时进行Encode-Mac-Encrypt   正是我的理论实例所表明的是不安全。

为了真实性,您应该放弃CBC模式并切换到GCM模式。 GCM是一种经过身份验证的加密模式,它将机密性和真实性结合到一种模式中,因此您不必组合基元(如AES / CBC和HMAC)。


  

或者我需要在发送的每个数据包开始时重置IV?

不,你设置IV一次然后忘记它。


  

问题来自所有这些例子,我不确定每次加密/解密需要做什么,以及我应该只在启动时做一次。

  1. 创建一次:EVP_CIPHER_CTX
  2. 请拨打一次以进行设置:EVP_CipherInit
  3. 您可以多次拨打此电话:EVP_CipherUpdate
  4. 请拨打一次以进行清理:EVP_CipherFinal
  5. OpenSSL wiki有很多使用EVP_*接口的例子。请参阅EVP Symmetric Encryption and DecryptionEVP Authenticated Encryption and DecryptionEVP Signing and Verifying

    所有示例都使用相同的模式:InitUpdate,然后是Final。无论是加密还是哈希都没关系。


    相关:您应该对此感兴趣:EVP Authenticated Encryption and Decryption。它的示例代码来自OpenSSL wiki。


    相关:您可以在线查找Viega,Messier和Chandra的Network Security with OpenSSL的副本。您可以考虑搜索副本并熟悉其中的一些概念。

答案 2 :(得分:2)

也为恢复旧线程而感到抱歉,但是LazerSharks在评论中两次询问了evp密码上下文。我在这里没有足够的声誉积分,无法添加一些评论,这就是我在这里回答的原因。 (即使现在Google搜索也不显示必要的信息) 摘自Pravir Chandra,Matt Messier和John Viega撰写的《使用OpenSSL进行网络安全》一书:

  

在我们可以开始加密或解密之前,我们必须分配和初始化一个密码上下文。密文上下文是一种数据结构,可跟踪所有相关状态,以便在一段时间内对数据进行加密或解密。例如,我们可以有多个   以CBC模式加密的数据。密码上下文将跟踪与每个密钥关联的密钥   流和在CBC模式的消息之间需要保留的内部状态。此外,在使用基于块的密码模式进行加密时,上下文对象会缓冲与块大小完全不匹配的数据,直到到达更多数据或显式刷新缓冲区为止,此时通常会适当地填充数据。

  通用密码上下文类型为EVP_CIPHER_CTX。我们可以通过调用EVP_CIPHER_CTX_init来初始化一个是动态分配的还是静态分配的,就像这样:

  EVP_CIPHER_CTX * x =(EVP_CIPHER_CTX *)malloc(sizeof(EVP_CIPHER_CTX));   EVP_CIPHER_CTX_init(x);