ページ 11

RSA暗号について

Posted: 2014年8月06日(水) 14:19
by だんごさん
前回(AESの質問)と同じく、RSA暗号について分からない点があり、調べてもあいまいなことしか書いてなかったりそもそも載っていなかったりと不明な点がありますので、こちらで質問させていただきます。

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

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

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

Re: RSA暗号について

Posted: 2014年8月06日(水) 18:29
by h2so5
だんごさん さんが書きました:  ・作成した公開鍵と秘密鍵を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が公開鍵にあたります。

Re: RSA暗号について

Posted: 2014年8月07日(木) 18:02
by だんごさん
h2so5 さんが書きました:目的によります。
だんごさん さんが書きました:前回AES暗号が出来上がりましたので、それをRSAを使って相手に送信したいのです。
すみません。目的は上記ではだめですか?目的とはどういったことでしょうか?

Re: RSA暗号について

Posted: 2014年8月08日(金) 23:02
by h2so5
AESとRSAを組み合わせる、ということしか分からないのでなんとも言えません。
RSAは単なるアルゴリズムですので、どのように暗号を運用するかは別の話です。

Re: RSA暗号について

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

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

Re: RSA暗号について

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

Re: RSA暗号について

Posted: 2014年8月26日(火) 03:27
by だんごさん
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で文字列化して送信し、また戻して代入する形で良いでしょうか?

Re: RSA暗号について

Posted: 2014年8月27日(水) 11:15
by h2so5
RSA_newを使って初期化してください。

Re: RSA暗号について

Posted: 2014年8月30日(土) 11:02
by sleep
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;
}
なかなか斬新な発想をされますね。

Re: RSA暗号について

Posted: 2014年8月30日(土) 18:37
by h2so5
途中でfinallyにジャンプすると初期化していないポインタに対してfreeを実行することになるので危険です。

Re: RSA暗号について

Posted: 2014年8月30日(土) 22:28
by sleep
はい、ご指摘ありがとうございます。
掲示の際、文字を読みやすくするために削除させていただきました。
必要とされている方に、必要な情報は伝えれたと思っています。

Re: RSA暗号について

Posted: 2014年9月08日(月) 19:26
by だんごさん
通信の方で詰まっていて遅れてしまいました。
検証ソースありがとうございます!だいぶ出来上がりました。

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

Re: RSA暗号について

Posted: 2014年9月08日(月) 19:58
by sleep
だんごさん さんが書きました:通信の方で詰まっていて遅れてしまいました。
検証ソースありがとうございます!だいぶ出来上がりました。

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

Re: RSA暗号について

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

Re: RSA暗号について

Posted: 2014年9月09日(火) 02:39
by sleep
だんごさん さんが書きました:詳しく調べてみました。
実は送信時に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 を格納するために必要と判断されたサイズが確保されているだけです。

Re: RSA暗号について

Posted: 2014年9月10日(水) 02:20
by だんごさん
できました…!
トピックを立てて1ヵ月になりましたが、みなさんありがとうございました!

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

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