我有一个单线程客户端/服务器应用程序,需要对其网络通信进行加密和解密.我计划使用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我发出去了?
小智.. 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(),因为它们可以重用现有的上下文,而无需在每次调用时分配和释放它.
换句话说,您需要在每次使用之前重新初始化上下文,但是您可以反复使用相同的上下文而无需创建(分配)新的上下文.
我有一个单线程客户端/服务器应用程序,需要对其网络通信进行加密和解密.我计划使用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)方案中,编写关于IPSec,SSL/TLS和SSH的认证加密的开创性论文的人:最后调用:(加密 - 然后-TAC for TLS和DTLS)建议标准:
我在2001年的论文中的技术结果是正确的,但关于SSL/TLS的结论是错误的.我假设TLS使用新的IV并且MAC是在编码的明文上计算的,即Encode-Mac-Encrypt,而TLS正在进行Mac-Encode-Encrypt,这正是我的理论示例显示的不安全.
为了真实性,您应该放弃CBC模式并切换到GCM模式.GCM是一种经过身份验证的加密模式,它将机密性和真实性结合到一种模式中,因此您无需组合基元(如AES/CBC和HMAC).
或者这是我需要在发送的每个数据包开始时重置IV的地方?
不,你设置IV一次然后忘记它.
问题来自所有这些例子,我不确定在每次加密/解密时需要做什么,以及我应该只在启动时做一次.
创建一次: EVP_CIPHER_CTX
调用此设置一次: EVP_CipherInit
根据您的喜好多次调用: EVP_CipherUpdate
将此调用一次以进行清理: EVP_CipherFinal
OpenSSL wiki有很多使用这些EVP_*
接口的例子.请参阅EVP对称加密和解密,EVP认证加密和解密以及EVP签名和验证.
所有的例子都使用相同的模式:Init
,Update
然后Final
.它的加密或散列并不重要.
相关:您应该对此感兴趣:EVP Authenticated Encryption and Decryption.它的示例代码来自OpenSSL wiki.
相关:您可以在线找到Viega,Messier和Chandra的Network Security与OpenSSL的副本.您可以考虑搜索副本并熟悉其中的一些概念.
很抱歉恢复旧线程,但我注意到接受的答案中出现以下错误:
在第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(),因为它们可以重用现有的上下文,而无需在每次调用时分配和释放它.
换句话说,您需要在每次使用之前重新初始化上下文,但是您可以反复使用相同的上下文而无需创建(分配)新的上下文.