C++ 如何将openssl EVP库与低级DES函数一起使用?
因此,我花了几个小时在谷歌搜索结果和一些与openssl函数相关的手册页中挖掘,试图找出如何将EVP函数与3DES加密结合使用。现在,我从C++ 如何将openssl EVP库与低级DES函数一起使用?,c++,encryption,openssl,cryptography,C++,Encryption,Openssl,Cryptography,因此,我花了几个小时在谷歌搜索结果和一些与openssl函数相关的手册页中挖掘,试图找出如何将EVP函数与3DES加密结合使用。现在,我从中获得了使用这些函数的代码: DES\u ede2\u cbc\u encrypt() DES\u set\u奇偶校验() DES\u set\u key\u checked() DES\u ecb2\u encrypt() 我的理解是,通过使用EVP函数,我可以统一处理3DES的ECB和CBC模式之间的加密/解密逻辑(我上面列表中的第一个和最后一个函数)
中获得了使用这些函数的代码:
DES\u ede2\u cbc\u encrypt()
DES\u set\u奇偶校验()
DES\u set\u key\u checked()
DES\u ecb2\u encrypt()
evp.h
标题中,我看到了类似evp_des_ede3_ecb
和evp_des_ede3_cbc
的内容,但我不知道如何使用它们。由于奇怪的方式,你必须设置的DES键(使用2个功能在中间从我的列表上方),我不知道什么加载键会像在EVP的方式。
如何将DES与EVP一起使用?如果有人能提供加密、解密和密钥设置的示例,这将非常有帮助。我试图在C++中封装所有类似的C代码,并使用STL对象/算法。我希望我的“DES”包装在DES的不同密码模式之间语义相同。我不确定这是否可行,但这就是我尝试使用EVP的原因。我认为您想要做的应该是可行的。EVPAPI主要是使用所有参数初始化上下文对象,然后在不知道上下文对象内部内容的情况下使用上下文对象。您甚至可以从OpenSSL允许您提供不需要的参数这一事实中获益,例如在初始化ECB模式的上下文时提供IV(将被忽略) 在进入EVP版本之前,让我们先谈谈您发布的函数 OpenSSL将DES密钥的生成分为三个步骤:
RAND\u DRBG\u字节
和RAND\u字节
)。第二步是因为DES密钥的某些位对密码强度没有贡献;因此,按照惯例,它们被设置为提供奇数奇偶校验的密钥字节。这是DES_set_odd_parity
的功能(有关更多说明,请参阅)。最后一步在OpenSSL中有几个选项:(a)信任用户提供了一个好的密钥,并展开该密钥;或者(b)检查用户提供的内容以确保它不是弱密钥,并在展开密钥计划之前检查它是否具有奇偶校验。后者由您列出的功能执行,DES\u set\u key\u checked
。前者更可靠,是DES\u set\u key\u unchecked
好吧,那么为什么这些都有用呢?好的,它在API的EVP版本中都有一个直接的模拟。使用DES函数,可以执行以下操作:
RAND_bytes
(或等效项)生成随机键DES\u set\u odd\u奇偶校验
设置奇偶校验位DES\u set\u key\u checked
展开密钥计划DES_uuencrypt
以使用展开密钥计划进行加密EVP\u CIPHER\u CTX\u ctrl(CTX,EVP\u ctrl\u RAND\u KEY,0,dest\u buf)
生成一个与已初始化EVP\u CIPHER\u CTX*CTX的密码相应的随机密钥。此步骤还通过调用DES\u set\u odd\u parity
在引擎盖下设置奇数奇偶校验。请注意,假定dest_buf足够大,可以容纳ctx
配置的密钥类型。请参见中的第280行
EVP_EncryptInit
传递密钥,在引擎盖下调用DES_set_key\u unchecked
以展开密钥计划并将其存储在上下文中。请注意,这是set key的未选中变体;EVPAPI只是假设您提供了一个好的密钥。请参见中的第226行(用于双键ede)uint8_t twokey[16];
EVP_EncryptInit(ctx, EVP_des_ede_cbc(), NULL, NULL);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, twokey);
EVP_EncryptInit(ctx, NULL, twokey, iv);
另外请注意,如果您已经有了密钥,则不需要OpenSSL来随机生成密钥EVP_EncryptInit
非常乐意信任您提供的任何密钥
这里有一个相当长的示例,使用硬编码密钥,但使用openssl函数来更正其奇偶校验
#include <openssl/evp.h>
#include <openssl/des.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
int res;
uint8_t key[16] = {
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87, 0x98
};
uint8_t iv[8] = {
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
};
uint8_t message[16] = {0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf};
uint8_t ciphertext[24] = {0}; //leave room for padding!
int ciphertext_total = 0;
uint8_t decrypted [16] = {0};
int decrypted_total = 0;
//Select our cipher of choice: 2-key 3DES in CBC mode (hence the IV)
const EVP_CIPHER *tdea_ede = EVP_des_ede_cbc();
printf("hardcoded key: ");
{
int i;
for(i=0; i< (int)sizeof(key); i++)
{
printf("%02x ", key[i]);
}
printf("\n");
}
//Note I have to set parity on each of the keys, and I'm doing 2-key 3DES
//DES_cblock is an annoying typdef of uchar[8]
DES_set_odd_parity((DES_cblock *)key);
DES_set_odd_parity((DES_cblock *)(key+8));
printf("key with odd parity: ");
{
int i;
for(i=0; i< (int)sizeof(key); i++)
{
printf("%02x ", key[i]);
}
printf("\n");
}
printf("Message: ");
{
int i;
for(i=0; i< (int)sizeof(message); i++)
{
printf("%02x ", message[i]);
}
printf("\n");
}
/* encrypt */
{
int outl = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit(ctx, tdea_ede, key, iv);
res = EVP_EncryptUpdate(ctx, ciphertext, &outl, message, (int)sizeof(message));
printf("Update wrote %d bytes\n", outl);
ciphertext_total += outl;
EVP_EncryptFinal(ctx, ciphertext + ciphertext_total, &outl);
printf("Final wrote %d bytes\n", outl);
ciphertext_total += outl;
}
printf("Ciphertext: ");
{
int i;
for(i=0; i<ciphertext_total; i++)
{
printf("%02x ", ciphertext[i]);
}
printf("\n");
}
/* decrypt */
{
int outl = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit(ctx, tdea_ede, key, iv);
res = EVP_DecryptUpdate(ctx, decrypted, &outl, ciphertext, ciphertext_total );
printf("Update wrote %d bytes\n", outl);
decrypted_total += outl;
EVP_DecryptFinal(ctx, decrypted + decrypted_total, &outl);
printf("Final wrote %d bytes\n", outl);
decrypted_total += outl;
}
printf("Decrypted: ");
{
int i;
for(i=0; i<decrypted_total; i++)
{
printf("%02x ", decrypted[i]);
}
printf("\n");
}
}
我承认,我很惊讶看到密文比消息大,但我记得OpenSSL默认应用填充
如果您不熟悉evpapi的init/update/final模型,请注意它是为流设计的。您可以任意多次调用update,只有当它有足够的数据来处理一个块时,您才会看到它写入任何输出。这就是为什么会有“最终”的原因…如果有一个在飞行中,则填充所有剩余数据并处理最终块
另外,请注意,该示例泄漏了EVP\u CIPHER\u CTX对象……这些对象应该在某个时候被释放。在EVP中,
DES\u ecb2\u encrypt()
等效项如何工作?我相信它没有静脉注射。我能把那个参数nullptr
留下吗?我的密钥已经生成了,我只需要在上面设置奇偶校验。但是设置奇偶校验是不必要的吗?在EVP中有没有一种方法可以为已经创建的密钥添加奇偶校验?不要介意我上面评论的后半部分:我错过了t
$ ./a.out
hardcoded key: 11 22 33 44 55 66 77 88 21 32 43 54 65 76 87 98
key with odd parity: 10 23 32 45 54 67 76 89 20 32 43 54 64 76 86 98
Message: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
Update wrote 16 bytes
Final wrote 8 bytes
Ciphertext: 5d f9 44 ff 82 0b c3 47 90 be 11 fb 62 01 15 f0 65 45 f6 05 3f fa 81 96
Update wrote 16 bytes
Final wrote 0 bytes
Decrypted: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f