RSA暗号について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
だんごさん
記事: 273
登録日時: 12年前

RSA暗号について

#1

投稿記事 by だんごさん » 9年前

前回(AESの質問)と同じく、RSA暗号について分からない点があり、調べてもあいまいなことしか書いてなかったりそもそも載っていなかったりと不明な点がありますので、こちらで質問させていただきます。

C言語でOpenSSLのRSA暗号を使い通信するソフトを作っています。
前回AES暗号が出来上がりましたので、それをRSAを使って相手に送信したいのです。
質問内容をまとめました。

 ・作成した公開鍵と秘密鍵をPEMファイルに出力してそのデータ(公開鍵)を相手に送信するのか。
 ・秘密鍵をPEMファイルとして出力した際、セキュリティ的に安全か。
 ・そもそも鍵をPEMとして出力する必要があるのか。
 ・もし出力しなくてよい場合、どのデータ(鍵)を相手に渡すのか。

サンプルなどを見て作っていたのですが、多種多様な物ばかりでRSAについて理解できずにいます。
どうかよろしくお願いします。
 Dango San

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: RSA暗号について

#2

投稿記事 by h2so5 » 9年前

だんごさん さんが書きました:  ・作成した公開鍵と秘密鍵をPEMファイルに出力してそのデータ(公開鍵)を相手に送信するのか。
目的によります。
だんごさん さんが書きました:  ・秘密鍵をPEMファイルとして出力した際、セキュリティ的に安全か。
PEMは単なるフォーマットなので安全かどうかは分かりません。
パスフレーズ付きのPEMファイルを作成することも可能です。
だんごさん さんが書きました:  ・そもそも鍵をPEMとして出力する必要があるのか。
目的によります。アプリケーションがPEMにしか対応していないならPEMで出力する必要があるでしょう。
だんごさん さんが書きました:  ・もし出力しなくてよい場合、どのデータ(鍵)を相手に渡すのか。
OpenSSLの鍵の構造体はこのようになっていますが
struct
{
BIGNUM *n; // public modulus
BIGNUM *e; // public exponent
BIGNUM *d; // private exponent
BIGNUM *p; // secret prime factor
BIGNUM *q; // secret prime factor
BIGNUM *dmp1; // d mod (p-1)
BIGNUM *dmq1; // d mod (q-1)
BIGNUM *iqmp; // q^-1 mod p
// ...
};
nとeが公開鍵にあたります。

だんごさん
記事: 273
登録日時: 12年前

Re: RSA暗号について

#3

投稿記事 by だんごさん » 9年前

h2so5 さんが書きました:目的によります。
だんごさん さんが書きました:前回AES暗号が出来上がりましたので、それをRSAを使って相手に送信したいのです。
すみません。目的は上記ではだめですか?目的とはどういったことでしょうか?
 Dango San

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: RSA暗号について

#4

投稿記事 by h2so5 » 9年前

AESとRSAを組み合わせる、ということしか分からないのでなんとも言えません。
RSAは単なるアルゴリズムですので、どのように暗号を運用するかは別の話です。

だんごさん
記事: 273
登録日時: 12年前

Re: RSA暗号について

#5

投稿記事 by だんごさん » 9年前

h2so5 さんが書きました:AESとRSAを組み合わせる、ということしか分からないのでなんとも言えません。
AESの共通鍵をRSAを使い暗号化して送信するために、まずRSAの公開鍵を相手に渡す作業を行いたいです。
説明が下手で申し訳ないです…。

もしPEMファイルに出力せずにRSA構造体のnとeを相手に送ったとして、暗号化関数に渡すRSA構造体の作成はどう行うのでしょうか?
仮にPEMだと、PEM_read_RSAPublicKeyでRSA構造体が返されますが、nとeを送った場合RSA構造体にnとeを直接入れてもいいのでしょうか?
 Dango San

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: RSA暗号について

#6

投稿記事 by h2so5 » 9年前

だんごさん さんが書きました: もしPEMファイルに出力せずにRSA構造体のnとeを相手に送ったとして、暗号化関数に渡すRSA構造体の作成はどう行うのでしょうか?
仮にPEMだと、PEM_read_RSAPublicKeyでRSA構造体が返されますが、nとeを送った場合RSA構造体にnとeを直接入れてもいいのでしょうか?
おそらく直接入れても大丈夫だと思います。

だんごさん
記事: 273
登録日時: 12年前

Re: RSA暗号について

#7

投稿記事 by だんごさん » 9年前

h2so5 さんが書きました:
だんごさん さんが書きました: もしPEMファイルに出力せずにRSA構造体のnとeを相手に送ったとして、暗号化関数に渡すRSA構造体の作成はどう行うのでしょうか?
仮にPEMだと、PEM_read_RSAPublicKeyでRSA構造体が返されますが、nとeを送った場合RSA構造体にnとeを直接入れてもいいのでしょうか?
おそらく直接入れても大丈夫だと思います。
すみません、自分で「nとeを直接入れてもいいか」と聞きましたがやり方が分かりませんでした…。
nとeを代入する前にRSA構造体は初期化しなければならないと思うのですが、そういった関数はあるのでしょうか?
またnとeはbignum_st構造体からなっているのですが、単純にBN_bn2hexで文字列化して送信し、また戻して代入する形で良いでしょうか?
 Dango San

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: RSA暗号について

#8

投稿記事 by h2so5 » 9年前

RSA_newを使って初期化してください。

sleep

Re: RSA暗号について

#9

投稿記事 by sleep » 9年前

h2so5 さんが書きました:
だんご さんが書きました: もしPEMファイルに出力せずにRSA構造体のnとeを相手に送ったとして、暗号化関数に渡すRSA構造体の作成はどう行うのでしょうか?
仮にPEMだと、PEM_read_RSAPublicKeyでRSA構造体が返されますが、nとeを送った場合RSA構造体にnとeを直接入れてもいいのでしょうか?
おそらく直接入れても大丈夫だと思います。
検証した結果、大丈夫でした。
"// 3.2. get public key from the clone" で n と e のみコピーしたRSA構造体からpublickey抽出をやっています。

[環境]CentOS 6.5, gcc 4.9.0, binutils 2.24, openssl 1.0.1e-16.el6_5.15

コード:

#include <openssl/rsa.h>
#include <openssl/pem.h>

#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
using namespace std;

void print(BIO* pbio)
{
  string key;
  char buff[512];
  int readbytes;

  while((readbytes = BIO_gets(pbio, buff, sizeof(buff))) > 0) {
    key.append(buff, readbytes);
  }

  cout << key << endl;
}

bool generate_rsa_key()
{
    int ret = 0;

    BIGNUM* bignum;

    RSA* rsa;
    BIO* pbio_private;
    BIO* pbio_public;

    RSA* clone;
    BIO* pbio_clone;


    // 1. generate rsa key
    //-------------------------------------------------
    bignum = BN_new();
    ret = BN_set_word(bignum, RSA_F4);
    if(ret != 1) goto finally;

    rsa = RSA_new();
    ret = RSA_generate_key_ex(rsa, 2048, bignum, NULL);
    if(ret != 1) goto finally;
    //-------------------------------------------------


    // 2. get private key
    //-------------------------------------------------
    //BIO* pbio_private = BIO_new_file("private.pem", "w+");  //output to file
    pbio_private = BIO_new(BIO_s_mem());  //output to memory
    ret = PEM_write_bio_RSAPrivateKey(pbio_private, rsa, NULL, NULL, 0, NULL, NULL);
    if(ret != 1) goto finally;
    //-------------------------------------------------
    print(pbio_private);


    // 3.1. get public key
    //-------------------------------------------------
    //BIO* pbio_public = BIO_new_file("public.pem", "w+");  //output to file
    pbio_public = BIO_new(BIO_s_mem());  //output to memory
    ret = PEM_write_bio_RSAPublicKey(pbio_public, rsa);
    if(ret != 1) goto finally;
    //-------------------------------------------------
    print(pbio_public);


    // 3.2. get public key from the clone
    //-------------------------------------------------
    clone = RSA_new();

    // n copy
    clone->n = (BIGNUM*)malloc(sizeof(BIGNUM));
    memcpy(clone->n, rsa->n, sizeof(BIGNUM));
    clone->n->d = (BN_ULONG*)malloc(sizeof(BN_ULONG) * rsa->n->dmax);
    memcpy(clone->n->d, rsa->n->d, sizeof(BN_ULONG) * rsa->n->dmax);
    // e copy
    clone->e = (BIGNUM*)malloc(sizeof(BIGNUM));
    memcpy(clone->e, rsa->e, sizeof(BIGNUM));
    clone->e->d = (BN_ULONG*)malloc(sizeof(BN_ULONG) * rsa->e->dmax);
    memcpy(clone->e->d, rsa->e->d, sizeof(BN_ULONG) * rsa->e->dmax);

    pbio_clone = BIO_new(BIO_s_mem());  //output to memory
    ret = PEM_write_bio_RSAPublicKey(pbio_clone, clone);
    if(ret != 1) goto finally;
    //-------------------------------------------------
    print(pbio_clone);


    // 4. finally
    //-------------------------------------------------
finally:
    BIO_free_all(pbio_clone);
    BIO_free_all(pbio_public);
    BIO_free_all(pbio_private);
    RSA_free(clone);
    RSA_free(rsa);
    BN_free(bignum);

    return (ret == 1);
    //-------------------------------------------------
}

int main()
{
    generate_rsa_key();
    return 0;
}
なかなか斬新な発想をされますね。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: RSA暗号について

#10

投稿記事 by h2so5 » 9年前

途中でfinallyにジャンプすると初期化していないポインタに対してfreeを実行することになるので危険です。

sleep

Re: RSA暗号について

#11

投稿記事 by sleep » 9年前

はい、ご指摘ありがとうございます。
掲示の際、文字を読みやすくするために削除させていただきました。
必要とされている方に、必要な情報は伝えれたと思っています。

だんごさん
記事: 273
登録日時: 12年前

Re: RSA暗号について

#12

投稿記事 by だんごさん » 9年前

通信の方で詰まっていて遅れてしまいました。
検証ソースありがとうございます!だいぶ出来上がりました。

ですが、現在復号の時にエラーが出てしまいます。
相手から自分の渡した公開鍵で暗号して送ってもらい、こちら側で復号しようとしたところ、
error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
とエラーが出ます。
色々とデバッグしてみたのですが見当たるものはなく、そもそもこのエラーが何を示しているのかが分かりません。
どういった時に出るのか、ヒントをくれませんでしょうか?
 Dango San

sleep

Re: RSA暗号について

#13

投稿記事 by sleep » 9年前

だんごさん さんが書きました:通信の方で詰まっていて遅れてしまいました。
検証ソースありがとうございます!だいぶ出来上がりました。

ですが、現在復号の時にエラーが出てしまいます。
相手から自分の渡した公開鍵で暗号して送ってもらい、こちら側で復号しようとしたところ、
error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02
とエラーが出ます。
色々とデバッグしてみたのですが見当たるものはなく、そもそもこのエラーが何を示しているのかが分かりません。
どういった時に出るのか、ヒントをくれませんでしょうか?
普通は、暗号化した公開鍵に対応する秘密鍵以外で復号しようとすると出ます。

だんごさん
記事: 273
登録日時: 12年前

Re: RSA暗号について

#14

投稿記事 by だんごさん » 9年前

詳しく調べてみました。
実は送信時にBIGNUMの値をBN_bn2hexで文字列化しています。送りやすいのと管理のしやすさのためです。
文字列化前はnの中身が
top:64
dmax:128
neg:0
となっているのですが、BN_hex2bnでBIGNUMに戻すと
top:64
dmax:64
neg:0
となってしまいます。
これは復号の時に影響が出るものでしょうか?
 Dango San

sleep

Re: RSA暗号について

#15

投稿記事 by sleep » 9年前

だんごさん さんが書きました:詳しく調べてみました。
実は送信時にBIGNUMの値をBN_bn2hexで文字列化しています。送りやすいのと管理のしやすさのためです。
文字列化前はnの中身が
top:64
dmax:128
neg:0
となっているのですが、BN_hex2bnでBIGNUMに戻すと
top:64
dmax:64
neg:0
となってしまいます。
これは復号の時に影響が出るものでしょうか?
復号には影響でません。

dmaxは、マニュアルにもあるとおり
オフトピック
dmax is the size of the d array that has been allocated.
ただの d 用に確保されたヒープメモリのサイズです。
BN_hex2bnの際、d を格納するために必要と判断されたサイズが確保されているだけです。

だんごさん
記事: 273
登録日時: 12年前

Re: RSA暗号について

#16

投稿記事 by だんごさん » 9年前

できました…!
トピックを立てて1ヵ月になりましたが、みなさんありがとうございました!

復号できなかった主な原因として、暗号化した文に終端文字が含まれていることでした。
暗号化した文字列をコピーする際に、256バイト分あるはずが、途中で終端文字に出会い中途半端なところで切られていました。
よって全てのコピー関数をmemcpyにしてサイズ指定することで解決いたしました。

本当にありがとうございました。
 Dango San

閉鎖

“C言語何でも質問掲示板” へ戻る