2017-12-03 28 views
-1

PKCS#1 RSAPublicKey形式でRSA公開鍵を生成しました。私はそうのように、このキーを使用してopenssl rsautlといくつかのデータを暗号化する:openssl rsautl "公開鍵を読み込めません"

$ openssl genrsa -out private_key.pem 512 
Generating RSA private key, 512 bit long modulus 
................++++++++++++ 
...++++++++++++ 
e is 65537 (0x10001) 
$ openssl rsa -in private_key.pem -RSAPublicKey_out -out public_key.pem 
writing RSA key 
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey public_key.pem 
unable to load Public Key 

はここで何が起こっていますか? opensslがそれ自身で生成した鍵を読み取ることができないのはなぜですか?どのフォーマットを読むことができますか?そして、より一般的に、なぜこれはso poorly documentedですか?

答えて

0

TL; DR: OpenSSLは廃止予定のいくつかのレガシーフォーマットをサポートしています。入力がRSA秘密鍵のペアの場合、openssl rsa -puboutの特別なケースがあるようです。最後に、OPの暗号化(およびそれに対応する復号化)を成功させる2つのコマンドシーケンスを与えます。 1つはPEMではなくDERを使用し、もう1つはDERを最初に放出し、次にそれをPEMに変換します...奇妙なことに、openssl rsaを使用して、入力がDERでエンコードされた公開鍵...とにかく、OPの最初の試みが失敗した理由の長い説明が以下にあります。 「なぜそんなに不十分な文書化がなされたのか」... OpenSSLへようこそ。グリフを高速化するので、ソースディレクトリ構造をよく学んでください。 format = FORMAT_PEMへ:)

長い説明(詳細には、OpenSSL 1.0.2mから採取)

のOpenSSL rsautlアプリデフォルト-inform引数(着信キー表現)。

それから、次のようなフォーマットを使用して、着信キーのリーダーを選択:

else if (format == FORMAT_PEMRSA) { 
    RSA *rsa; 
    rsa = PEM_read_bio_RSAPublicKey(key, NULL, 
            (pem_password_cb *)password_callback, 
            &cb_data); 
    /* ... */ 
} 
else if (format == FORMAT_PEM) { 
    pkey = PEM_read_bio_PUBKEY(key, NULL, 
           (pem_password_cb *)password_callback, 
           &cb_data); 

をので、私たちはPEM_read_bio_PUBKEYを使用することがあります。上記のFORMAT_PEMRSAのエントリに注意してください... PEM_read_bio_RSAPublicKeyにつながるパスを同時に開発します。

# define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ 
type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ 
{ \ 
    return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \ 
} 
:これらの読者の両方がいくつかのマクロ順番にと実際の定義を構築する

# define IMPLEMENT_PEM_read(name, type, str, asn1) \ 
    IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ 
    IMPLEMENT_PEM_read_fp(name, type, str, asn1) 

を使用することを

# define IMPLEMENT_PEM_rw(name, type, str, asn1) \ 
    IMPLEMENT_PEM_read(name, type, str, asn1) \ 
    IMPLEMENT_PEM_write(name, type, str, asn1) 

# define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \ 
    IMPLEMENT_PEM_read(name, type, str, asn1) \ 
    IMPLEMENT_PEM_write_const(name, type, str, asn1)  

に拡大

crypto/pem/pem_all.c:427:IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY) 
crypto/pem/pem_all.c:241:IMPLEMENT_PEM_rw_const(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC, RSAPublicKey) 

経由で定義されています

r noteはバージョンの場合はPEM_STRING_PUBLICPEM_read_bio_RsaPublicKeyバージョンの場合はPEM_STRING_RSA_PUBLICとして渡される第3引数、strです。これらの文字列は、それぞれ、

./crypto/pem/pem.h:122:# define PEM_STRING_PUBLIC  "PUBLIC KEY" 
./crypto/pem/pem.h:124:# define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" 

PEM_ASN1_read_bioの実装を見ると、我々はそれを部分に分割することも、重要なファイルを読み込みPEM_bytes_read_bio

void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, 
         pem_password_cb *cb, void *u) 
{ 
    const unsigned char *p = NULL; 
    unsigned char *data = NULL; 
    long len; 
    char *ret = NULL; 

    if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u)) 
     return NULL; 
    /* ... */ 

PEM_bytes_read_bio呼び出して参照してください。 nm-----秒の間にマーカーを取得します(-----BEGIN RSA PUBLIC KEY-----など)。check_pemでチェックされます。nmファイルで見つかった文字列、およびnameで次のように

int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, 
         const char *name, BIO *bp, pem_password_cb *cb, 
         void *u) 
{ 
    EVP_CIPHER_INFO cipher; 
    char *nm = NULL, *header = NULL; 
    unsigned char *data = NULL; 
    long len; 
    int ret = 0; 

    for (;;) { 
     if (!PEM_read_bio(bp, &nm, &header, &data, &len)) { 
      if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) 
       ERR_add_error_data(2, "Expecting: ", name); 
      return 0; 
     } 
     if (check_pem(nm, name)) 

そしてcheck_pemチェックは、ハードコーディングされPEM_read_bio_XXX関数であるから渡されました。

static int check_pem(const char *nm, const char *name) 
{ 
    /* Normal matching nm and name */ 
    if (!strcmp(nm, name)) 
     return 1;   

    /* special cases for 
     PKCS8 format (BEGIN PRIVATE KEY or BEGIN ENCRYPTED PRIVATE KEY) 
     Various things ending in PARAMETERS 
     Various X509 related files 
     PKCS7 format (BEGIN PKCS7 or BEGIN PKCS7 SIGNED DATA) 
     CMS things (BEGIN CMS) */ 

    /* ... */ 

それはちょうどnamenmstrcmpを行います。だから、PEM_read_bio_PUBKEYでRSA公開鍵を正常に読むには、それは-----BEGIN PUBLIC KEY-----で始まる必要がありますが、OPの指示で生成された鍵を見ると、-----BEGIN RSA PUBLIC KEY-----が見つかります。しかし、これはPEM_read_bio_RsaPublicKeyに対応する文字列です... -informを代わりに使用してformat = FORMAT_PEMRSAを選択し、rsautlに公開鍵を読み取ることができます。 rsautlは、str2fmtというファンクションを使用して、-inform引数を解析します。見てみましょう:

int str2fmt(char *s) 
{ 
    if (s == NULL) 
     return FORMAT_UNDEF; 
    if ((*s == 'D') || (*s == 'd')) 
     return (FORMAT_ASN1); 
    else if ((*s == 'T') || (*s == 't')) 
     return (FORMAT_TEXT); 
    else if ((*s == 'N') || (*s == 'n')) 
     return (FORMAT_NETSCAPE); 
    else if ((*s == 'S') || (*s == 's')) 
     return (FORMAT_SMIME); 
    else if ((*s == 'M') || (*s == 'm')) 
     return (FORMAT_MSBLOB); 
    else if ((*s == '1') 
      || (strcmp(s, "PKCS12") == 0) || (strcmp(s, "pkcs12") == 0) 
      || (strcmp(s, "P12") == 0) || (strcmp(s, "p12") == 0)) 
     return (FORMAT_PKCS12); 
    else if ((*s == 'E') || (*s == 'e')) 
     return (FORMAT_ENGINE); 
    else if ((*s == 'H') || (*s == 'h')) 
     return FORMAT_HTTP; 
    else if ((*s == 'P') || (*s == 'p')) { 
     if (s[1] == 'V' || s[1] == 'v') 
      return FORMAT_PVK; 
     else 
      return (FORMAT_PEM); 
    } else 
     return (FORMAT_UNDEF); 
} 

いいえ。 FORMAT_PEMRSAを返す方法はありません。

マーカを-----BEGIN PUBLIC KEY-----と言うように公開鍵ファイルを編集するとどうなりますか?

$ sed -e "s/RSA PUBLIC/PUBLIC/" public_key.pem > public_key_mod.pem    
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey public_key_mod.pem 
unable to load Public Key 

いいえ。

公開鍵をPEMではなくDERに抽出するとどうなりますか?

$ openssl rsa -in private_key.pem -out public_key.der -outform DER -pubout 
writing RSA key 
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey public_key.der -keyform DER 

$ openssl rsautl -decrypt -in encrypted_with_pub_key -inkey private_key.pem 
this is the cleartext 

成功!多分私達は、OpenSSLがrsautl

$ openssl rsa -in public_key.der -inform DER -pubin -out test.pem 
writing RSA key 
$ cat test.pem 
-----BEGIN PUBLIC KEY----- 
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM3uGdU6YtwI5S8K+GgddW8KhrzmSFVI 
6cvBT+XqOuSVo+n8VyUfADHw4rPxjy/dWDpyOxzWdTg8VZ77Vs06af8CAwEAAQ== 
-----END PUBLIC KEY----- 
$ echo "this is the cleartext" | openssl rsautl -encrypt -out encrypted_with_pub_key -pubin -inkey test.pem 

$ openssl rsautl -decrypt -in encrypted_with_pub_key -inkey private_key.pem 
this is the cleartext 

と互換性のある形式にDERキーを変換するために取得することができ、それは、入力としてBEGIN RSA PRIVATE KEYを取るときそうです...それはopenssl rsaのように見えるだけ時代遅れBEGIN RSA PUBLIC KEYフォームを書き込みます。

関連する問題