C++ 如何使用RSA正确交换对称aes密钥
我尝试使用OpenSSL库实现C++中的SSL握手 (在上下文中,因为节点通过网关通信,所以我不能使用已经实现的ssl套接字) 让我们有发送者和接收者C++ 如何使用RSA正确交换对称aes密钥,c++,openssl,aes,rsa,C++,Openssl,Aes,Rsa,我尝试使用OpenSSL库实现C++中的SSL握手 (在上下文中,因为节点通过网关通信,所以我不能使用已经实现的ssl套接字) 让我们有发送者和接收者 发送方将其证书发送给接收方 接收方从发送方发布密钥(包含在证书中)创建AES密钥 接收方使用发送方的pub_密钥加密AES密钥,然后使用其私钥加密AES密钥,并将其发送给发送方(及其证书) 发送方使用接收方的公钥解密,然后使用其私钥解密 使用RSA_PKCS1_填充进行公共加密 使用RSA_NO_填充进行私有加密 现在,私有解密部分的失败率约为5
error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
我不知道如何解决这个问题
全部代码:
#include <iostream>
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/aes.h"
#include "openssl/err.h"
#include <openssl/pem.h>
using namespace std;
int main(int argc, char *argv[]) {
int ret = 0;
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
srand(time(NULL));
X509 *sender_x, *receiver_x;
RSA *sender_priv_key, *sender_pub_key, *receiver_priv_key, *receiver_pub_key;
EVP_PKEY *sender_evp_key, *receiver_evp_key;
string sender_ssl_cert = "unit_test/ini/00000000000Wcert.pem";
string sender_ssl_key = "unit_test/ini/00000000000Wkey.pem";
string receiver_ssl_cert = "unit_test/ini/00000000000Rcert.pem";
string receiver_ssl_key = "unit_test/ini/00000000000Rkey.pem";
string ssl_ca="unit_test/ini/sitsroot.pem";
BIO *bio = BIO_new(BIO_s_mem());
unsigned char tmp_buf[2000 + 1];
unsigned char key[32], iv[32];
/** **************************************************************** */
/** ************************ READ FILES **************************** */
FILE *f;
if ((f = fopen(sender_ssl_cert.c_str(), "r")) == NULL) {
cout << "failed to open file " << sender_ssl_cert << endl;
return -1;
}
if ((sender_x = PEM_read_X509(f, NULL, NULL, NULL)) == NULL) {
cout << "failed to read cert file " << sender_ssl_cert << endl;
fclose(f);
return -1;
}
fclose(f);
if ((f = fopen(sender_ssl_key.c_str(), "r")) == NULL) {
cout << "failed to open file " << sender_ssl_key << endl;
return -1;
}
if ((sender_priv_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL)) == NULL) {
cout << "failed to read cert file " << sender_ssl_key << endl;
fclose(f);
return -1;
}
fclose(f);
if ((f = fopen(receiver_ssl_cert.c_str(), "r")) == NULL) {
cout << "failed to open file " << receiver_ssl_cert << endl;
return -1;
}
if ((receiver_x = PEM_read_X509(f, NULL, NULL, NULL)) == NULL) {
cout << "failed to read cert file " << receiver_ssl_cert << endl;
fclose(f);
return -1;
}
fclose(f);
if ((f = fopen(receiver_ssl_key.c_str(), "r")) == NULL) {
cout << "failed to open file " << receiver_ssl_key << endl;
return -1;
}
if ((receiver_priv_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL)) == NULL) {
cout << "failed to read cert file " << receiver_ssl_key << endl;
fclose(f);
return -1;
}
fclose(f);
/** ************************ READ FILES **************************** */
/** **************************************************************** */
/** **************************************************************** */
/** *********************** GENERATE KEY *************************** */
sender_evp_key = X509_get_pubkey(sender_x);
PEM_write_bio_PUBKEY(bio, sender_evp_key);
ret = BIO_read(bio, tmp_buf, 2000);
ret = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL, tmp_buf, ret, 5, key, iv);
if (ret != 32) {
cout << "Key size is " << ret << " bytes, should be 256 bits" << endl;
return -1;
}
/** *********************** GENERATE KEY *************************** */
/** **************************************************************** */
/** **************************************************************** */
/** *********************** ENCRYPT KEY **************************** */
sender_pub_key = EVP_PKEY_get1_RSA(sender_evp_key);
unsigned char *encrypted_key = (unsigned char*)malloc(RSA_size(sender_pub_key) * sizeof(unsigned char));
if ((ret = RSA_public_encrypt(32, key, encrypted_key, sender_pub_key, RSA_PKCS1_PADDING)) < 0) {
cout << "RSA_public_encrypt failed: " << ERR_error_string(ERR_get_error(), NULL) << endl;
return -1;
}
if ((ret = RSA_private_encrypt(ret, encrypted_key, encrypted_key, receiver_priv_key, RSA_NO_PADDING)) < 0) {
cout << "RSA_private_encrypt failed, " << ERR_error_string(ERR_get_error(), NULL) << endl;
return -1;
}
cout << "RSA_private_encrypt ret: " << ret << endl;
/** *********************** ENCRYPT KEY **************************** */
/** **************************************************************** */
/** **************************************************************** */
/** *********************** DECRYPT KEY **************************** */
if ((receiver_evp_key = X509_get_pubkey(receiver_x)) == NULL) cout << "receiver_evp_key NULL" << endl;
if ((receiver_pub_key = EVP_PKEY_get1_RSA(receiver_evp_key)) == NULL) cout << "receiver_pub_key NULL" << endl;
unsigned char *decrypted_key = (unsigned char*)malloc(RSA_size(receiver_pub_key) * sizeof(unsigned char) + 1);
if ((ret = RSA_public_decrypt(ret, encrypted_key, decrypted_key, receiver_pub_key, RSA_NO_PADDING)) < 0) {
cout << "RSA_public_decrypt failed, " << ERR_error_string(ERR_get_error(), NULL) << endl;
return -1;
}
cout << "RSA_public_decrypt ret: " << ret << endl;
if ((ret = RSA_private_decrypt(ret, decrypted_key, decrypted_key, sender_priv_key, RSA_PKCS1_PADDING)) < 0) {
cout << "RSA_private_decrypt failed, " << ERR_error_string(ERR_get_error(), NULL) << endl;
return -1;
}
cout << "RSA_private_decrypt ret: " << ret << endl;
/** *********************** DECRYPT KEY **************************** */
/** **************************************************************** */
return 0;
}
关于RSA_私有加密
这是我正在努力解决的主要问题(之前的问题只是我的错误)
编辑2:
RSA_public_encrypt ret: 128
RSA_size(sender_priv_key): 128
RSA_private_encrypt failed, error:04066084:rsa routines:RSA_EAY_PRIVATE_ENCRYPT:data too large for modulus
您的代码误用了strlen。
strlen
函数只能用于C样式的字符串,不能用于任意二进制数据
文档说明RSA\u private\u encrypt
和RSA\u private\u decrypt
返回加密/解密数据的长度。但是你可以调用strlen
上的encrypted_key
,它不是一个C风格的字符串——它只是一个没有简单结构的任意二进制数据块
您不需要对其调用strlen
,因为RSA\u private\u encrypt
返回其长度。你不能在上面调用strlen,因为它不是字符串
很多人对strlen(有时是sizeof)的工作有错误的印象。它们精确地定义了您必须理解的语义,以便正确使用这些函数。它们不能神奇地确定任意数据结构的大小。如果您不明确知道某个内容是C样式的字符串,请不要将其传递给任何str*
函数
想想看,
strlen
可能实现什么算法,只需查看指向加密数据第一个字节的指针就可以确定加密数据块的长度?你在期待魔术。哦,我的错,只是我刚刚比较了private encrypt和strlen的返回值,在前3-4次运行中,返回值是相同的,所以我假设字符串终止为null,很可能缓冲区开始时充满了零,而幸运的是,加密数据中刚好没有零。但是,您必须强制转换的事实应该是一个让步——谁将C样式字符串存储在unsigned char*
中,以便您在任何时候都必须强制转换,以便将它们传递给str*
函数?这没有多大意义。编辑我的答案,添加更多在其他方面失败的代码,实际上再次加密解密的密钥“数据对于模数来说太大”错误意味着您正在尝试加密大于RSA密钥大小的数据。很可能您应该加密一个随机的固定长度密钥,并使用该密钥通过对称算法加密解密的密钥。我添加了som调试输出,但public encrypt的返回值与私钥的大小相同
error:04066084:rsa routines:RSA_EAY_PRIVATE_ENCRYPT:data too large for modulus
RSA_public_encrypt ret: 128
RSA_size(sender_priv_key): 128
RSA_private_encrypt failed, error:04066084:rsa routines:RSA_EAY_PRIVATE_ENCRYPT:data too large for modulus