OpenSSL ライブラリを使用して c++ で ssl ハンドシェイクを実装しようとしています (コンテキストでは、ノードはゲートウェイを介して通信しているため、既に実装されている ssl ソケットは使用できません)
送信者と受信者を用意しましょう
- 送信者は自分の証明書を受信者に送信します
- 受信者は送信者の pub_key (証明書に含まれる) から AES キーを作成します
- 受信者は、送信者の pub_key を使用して AES キーを暗号化し、次にその秘密鍵を使用して AES キーを暗号化し、それを (証明書と共に) 送信者に送信します。
- 送信者は受信者の pub_key を使用して復号化し、次に秘密鍵を使用して復号化します
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をencrypt関数によって返されるret値に変更した後、それは大丈夫になりましたが、ステップ3に進みましょう。このコードを最後に追加します(return 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 で、これが私が苦労している主な問題です (前の問題は私の間違いでした)
編集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