3

OpenSSL ライブラリを使用して c++ で ssl ハンドシェイクを実装しようとしています (コンテキストでは、ノードはゲートウェイを介して通信しているため、既に実装されている ssl ソケットは使用できません)

送信者と受信者を用意しましょう

  1. 送信者は自分の証明書を受信者に送信します
  2. 受信者は送信者の pub_key (証明書に含まれる) から AES キーを作成します
  3. 受信者は、送信者の pub_key を使用して AES キーを暗号化し、次にその秘密鍵を使用して AES キーを暗号化し、それを (証明書と共に) 送信者に送信します。
  4. 送信者は受信者の 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
4

1 に答える 1

1

あなたのコードは誤用してstrlenいます。このstrlen関数は、Cスタイルの文字列でのみ使用でき、任意のバイナリデータでは使用できません。

ドキュメントには、暗号化/復号化されたデータの長さが記載されてRSA_private_encryptおり、返されます。RSA_private_decryptしかしstrlenencrypted_keyこれはCスタイルの文字列ではなく、単純な構造を持たない任意のバイナリデータのブロックにすぎません。

その長さを返すstrlenので、それを呼び出す必要はありません。RSA_private_encryptそして、それは文字列ではないので、それを呼び出すことはできません。strlen

多くの人がstrlen(そして時々sizeof)何をするかについて誤った印象を持っています。それらは正確に定義されたセマンティクスを持っており、それらの関数を適切に使用するために理解する必要があります。それらは、任意のデータ構造の大きさを魔法のように決定するものではありません。何かがCスタイルの文字列であることが明確にわからない場合は、どのstr*関数にも渡さないでください。

考えてみてくださいstrlen。暗号化されたデータのブロックの長さを、そのデータの最初のバイトへのポインタを見るだけで判断できるアルゴリズムを実装できるでしょうか。あなたは魔法を期待しています。

于 2012-10-23T08:47:30.230 に答える