我尝试使用OpenSSL库在c ++中实现ssl握手 (在上下文中,因为节点通过网关进行通信,所以我不能使用已经实现的ssl套接字)
让我们有发件人和收件人
使用RSA_PKCS1_PADDING进行公共加密 使用RSA_NO_PADDING进行私有加密
现在,私人解密部分使用
失败了大约50%的时间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;
}
编辑: 在将strlen更改为由加密函数返回的ret值之后,这变成了okey 但是让我们转到第3步。 将此代码添加到最后(在返回0;语句之前)
/** **************************************************************** */
/** ******************* ANOTHER ENCRYPT KEY ************************ */
unsigned char *another_encrypted_key = (unsigned char*)malloc(RSA_size(receiver_pub_key) * sizeof(unsigned char));
if ((ret = RSA_public_encrypt(32, decrypted_key, another_encrypted_key, receiver_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, another_encrypted_key, another_encrypted_key, sender_priv_key, RSA_NO_PADDING)) < 0) {
cout << "RSA_private_encrypt failed, " << ERR_error_string(ERR_get_error(), NULL) << endl;
return -1;
}
/** ******************* ANOTHER ENCRYPT KEY ************************ */
/** **************************************************************** */
这导致大约15%的机会获得:
error:04066084:rsa routines:RSA_EAY_PRIVATE_ENCRYPT:data too large for modulus
在RSA_private_encrypt上 这是我努力的主要问题(之前的那个只是我的错误)
EDIT2:
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
答案 0 :(得分:1)
您的代码误用了strlen
。 strlen
函数只能用于C风格的字符串,而不能用于任意二进制数据。
文档指出RSA_private_encrypt
和RSA_private_decrypt
返回加密/解密数据的长度。但是你在strlen
上调用encrypted_key
不是一个C风格的字符串 - 它只是一个没有简单结构的任意二进制数据块。
您无需在其上调用strlen
,因为RSA_private_encrypt
会返回其长度。并且无法在其上调用strlen
,因为它不是字符串。
很多人对strlen
(有时是sizeof
)的行为都有错误的印象。它们具有精确定义的语义,您必须了解这些语义才能正确使用这些函数。他们并没有神奇地确定任意数据结构有多大。如果您没有特别知道某些内容是C风格的字符串,请不要将其传递给任何str*
函数。
考虑一下 - 只有通过查看指向该数据第一个字节的指针,strlen
可能实现哪种算法才能确定加密数据块的长度?你期待着魔法。