web-dev-qa-db-ja.com

ECC秘密鍵のPKCS#1形式への変換

ECC秘密鍵をRSA PKCS#1形式に変換する方法はありますか?最初にOpenSSLを使用してPKCS#8に変換してみました。

openssl pkcs8 -topk8 -nocrypt -in EC_key.pem -out pkcs8_key.pem

これにより、正しいPKCS8形式(私が想定しているもの)のpemファイルが生成されます

-----BEGIN PRIVATE KEY-----
[snip]
-----END PRIVATE KEY-----

その後、次のコマンドを使用してPKCS#8からPKCS#1に変換しようとすると、

openssl pkcs8 -inform pem -nocrypt -in pkcs8_key.pem -out pkcs1_key.pem

前のステップと同じファイルを取得します。

次のコマンドを使用して変換する場合:

openssl rsa –in pkcs8_key.pem –out pkcs1_key.pem

次のエラーが発生します。

47049676604576:error:0607907F:デジタルエンベロープルーチン:EVP_PKEY_get1_RSA:RSAキーが必要です:p_lib.c:279:

ECキーをRSA PKCS#1キーに変換できますか?そして、もしそうなら、どうですか?

14
Sid Said

ここでは、PKCS標準を編集する組織である「RSA Laboratories」と暗号化アルゴリズムであるRSAが少し混乱している可能性があります。 PKCS#1 はPKCS標準の1つであるため、RSA Laboratoriesによって編集されています。これは、RSAアルゴリズムについて話し、RSAアルゴリズムについてはonlyです。

特に、EC鍵はRSA鍵ではないため、楕円曲線(EC)鍵には「PKCS#1形式」などはありません。EC鍵はEC鍵であり、まったく同じ種類のオブジェクトではありません。


しかし、混乱はさらに広がっていますので、いくつかのレイヤーを解明しましょう。

PKCS#1はRSAについて話し、RSA秘密鍵のASN.1ベースのエンコーディングを定義します。次のようになります。

  RSAPrivateKey ::= SEQUENCE {
      version           Version,
      modulus           INTEGER,  -- n
      publicExponent    INTEGER,  -- e
      privateExponent   INTEGER,  -- d
      prime1            INTEGER,  -- p
      prime2            INTEGER,  -- q
      exponent1         INTEGER,  -- d mod (p-1)
      exponent2         INTEGER,  -- d mod (q-1)
      coefficient       INTEGER,  -- (inverse of q) mod p
      otherPrimeInfos   OtherPrimeInfos OPTIONAL
  }

ここでは、RSA公開/秘密鍵ペアを構成するさまざまな数学要素を認識しています。 ASN.1 に基づいているため、この種類のオブジェクトは( [〜#〜] der [〜#〜] を介して)いくつかのバイトにエンコードします。 OpenSSLは、このようなバイトシーケンスを生成および消費できます。ただし、これらのバイトを従来の(指定が不十分な)PEM形式にさらに再エンコードするのは一般的です。バイトは Base64 でエンコードされ、ヘッダーとフッターが追加され、エンコードされたオブジェクトの種類を指定します。

PKCS#1で定義されているRSA秘密鍵の生のASN.1ベースの形式では、キータイプの明確な識別を含まないバイトシーケンスが生成されることに注意することが重要です。その形式でDERエンコードされたRSA秘密鍵を読み取るアプリケーションは、RSA秘密鍵を想定している必要があることをあらかじめ知っている必要があります。 「RSA PRIVATE KEY」と書かれたPEMヘッダーは、その情報を提供します。

PKCS標準はPEMについて話していないため、鍵のタイプを特定するという問題に対する独自のソリューションを提供します。 PKCS#8 と呼ばれます。 PKCS#8形式のキーもASN.1ベースで、構造は次のようになります。

  PrivateKeyInfo ::= SEQUENCE {
     version Version,
     privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
     privateKey PrivateKey,
     attributes [0] Attributes OPTIONAL }

  Version ::= INTEGER {v1(0)} (v1,...)

  PrivateKey ::= OCTET STRING

これは、PKCS#8オブジェクトが他の形式のラッパーであることを意味します。 RSA秘密鍵の場合、ラッパーは(privateKeyAlgorithmフィールドを通じて)キーが実際にRSA鍵であることを示し、PrivateKeyフィールドの内容(OCTET STRING、つまり任意のバイトシーケンス)は、実際にはPKCS#1秘密鍵のDERエンコーディングです。

OpenSSLは、デフォルトでは、PKCS#8ファイルをDERエンコードされたバイトシーケンスとして存続させることはできません。再びPEMに変換し、今回は「BEGIN PRIVATE KEY」ヘッダーを追加します。エンコードされたオブジェクト(Base64を介して文字に変換される)にはすでに情報が含まれているため、このヘッダーはキータイプを指定しないことに注意してください。

(さらに複雑なこととして、PKCS#8はオプションで、多くの場合パスワードベースの秘密鍵の暗号化も定義しています;およびOpenSSLが実装する従来のPEMのような形式また、パスワードベースの暗号化に対するいくつかの一般的なサポートが含まれているため、ある種の暗号化を指定するラッパーの複数の組み合わせを持つことができ、完全な混乱としてのみ記述できるものになります。)

これはECキーについて何を示していますか? ECキーはPKCS#1では記述されていません(RSAについてのみ説明しています)。ただし、EC秘密鍵をバイトシーケンスに変換する方法を示す標準がある場合は、次のようになります。

  • そのバイトのシーケンスは、いくつかの明示的なテキストヘッダーを使用してOpenSSLによってPEMエンコードされる可能性があります。
  • 同じバイトシーケンスをPKCS#8オブジェクトにラップできます。

そして、これはまさに何が起こるかです。 ECキーのエンコード形式を定義する標準は SEC 1 です(名目上、EC暗号化の標準はANSI X9.62ですが、X9.62はSEC 1の多くを再利用しましたが、エンコードの仕様privateECキーはSEC 1にのみ存在します。X9.62は、公開キーのエンコードのみに関係するためです)。 SEC 1(セクションC.4)では、次のように定義されています。

  ECPrivateKey ::= SEQUENCE {
         version       INTEGER { ecPrivkeyVer1(1) },
         privateKey    OCTET STRING,
         parameters    [0] EXPLICIT ECDomainParameters OPTIONAL,
         publicKey     [1] EXPLICIT BIT STRING OPTIONAL
  }

したがって、エンコードされた秘密鍵には、秘密鍵自体(1 ..n-1範囲の整数が含まれます。ここで、nはカーブサブグループの順序)、オプションで使用されたカーブの説明または参照、およびオプションで公開鍵のコピー(他の方法で再計算できます)。

試してみよう。 OpenSSLを使用して、標準のNIST P-256曲線(誰もが実装して使用するthe曲線)に新しいECキーペアを生成します。

$ openssl ecparam -out ec1.pem -genkey -name prime256v1

これをec1.pemファイルで取得します。

$ cat ec1.pem
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBdVHnnzZmJm+Z1HAYYOZlvnB8Dj8kVx9XBH+6UCWlGUoAoGCCqGSM49
AwEHoUQDQgAEThPp/xgEov0mKg2s0GII76VkZAcCc//3quAqzg+PuFKXgruaF7Kn
3tuQVWHBlyZX56oOstUYQh3418Z3Gb1+yw==
-----END EC PRIVATE KEY-----

最初の要素( "EC PARAMETERS")は冗長です。使用されている曲線への参照が含まれていますが、この情報は2番目の要素にも含まれています。そこで、テキストエディタを使用して「ECパラメータ」を削除し、「ECプライベートキー」の部分のみを残します。これで、ec1.pemファイルは次のようになります。

$ cat ec1.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBdVHnnzZmJm+Z1HAYYOZlvnB8Dj8kVx9XBH+6UCWlGUoAoGCCqGSM49
AwEHoUQDQgAEThPp/xgEov0mKg2s0GII76VkZAcCc//3quAqzg+PuFKXgruaF7Kn
3tuQVWHBlyZX56oOstUYQh3418Z3Gb1+yw==
-----END EC PRIVATE KEY-----

OpenSSLを使用してその構造をデコードできます。

$ openssl asn1parse -i -in ec1.pem
    0:d=0  hl=2 l= 119 cons: SEQUENCE          
    2:d=1  hl=2 l=   1 prim:  INTEGER           :01
    5:d=1  hl=2 l=  32 prim:  OCTET STRING      [HEX DUMP]:17551E79F3666266F99D4701860E665BE707C0E3F24571F57047FBA5025A5194
   39:d=1  hl=2 l=  10 cons:  cont [ 0 ]        
   41:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   51:d=1  hl=2 l=  68 cons:  cont [ 1 ]        
   53:d=2  hl=2 l=  66 prim:   BIT STRING

SEC 1で定義されている、予想されるASN.1構造を認識します。値1のINTEGER(versionフィールド)、OCTET STRING(privateKey自体、数学的な秘密鍵のビッグエンディアン符号なしエンコーディング)、使用された曲線への参照([0]でタグ付けされた)(ASN.1オブジェクトでは、OID 1.2.840.10045.3.1。 7; OpenSSLはそれを「prime256v1」という名前に変換し、([1]でタグ付けされた)公開鍵のコピーを作成します。

これを(暗号化されていない)PKCS#8形式に変換できます。

$ openssl pkcs8 -topk8 -nocrypt -in ec1.pem -out ec2.pem

これはこれをもたらします:

$ cat ec2.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgF1UeefNmYmb5nUcB
hg5mW+cHwOPyRXH1cEf7pQJaUZShRANCAAROE+n/GASi/SYqDazQYgjvpWRkBwJz
//eq4CrOD4+4UpeCu5oXsqfe25BVYcGXJlfnqg6y1RhCHfjXxncZvX7L
-----END PRIVATE KEY-----

openSSLでデコードできること:

$ openssl asn1parse -i -in ec2.pem
    0:d=0  hl=3 l= 135 cons: SEQUENCE          
    3:d=1  hl=2 l=   1 prim:  INTEGER           :00
    6:d=1  hl=2 l=  19 cons:  SEQUENCE          
    8:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey
   17:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   27:d=1  hl=2 l= 109 prim:  OCTET STRING      [HEX DUMP]:306B0201010420(...)

(16進ダンプを切り捨てました。)この構造は、確かにPKCS#8オブジェクトです。

  • アルゴリズム識別子フィールドは、「これにはECキーが含まれています」(技術的には、「id-ecPublicKey」という名前の識別子を使用しますが、これはPKCS#8ファイルで発生するため、これがECprivatekey)。
  • このファイルには、使用された曲線への参照がキーパラメータとして含まれています。
  • キー値はOCTET STRINGのコンテンツにエンコードされます。そのOCTET STRINGをさらにデコードすると、SEC 1で指定されたとおりにエンコードされたEC秘密キーが見つかります(奇妙なことに、カーブへの参照は、キーパラメーターに既に存在するため、その場合、省略されているように見えます)。

次のようにして、他の方向(PKCS#8からraw SEC 1形式へ)に変換できます。

$ openssl ec -in ec2.pem -out ec3.pem

次に、ファイルec3.pemに、ファイルec1.pemとまったく同じように、ヘッダー「BEGIN EC PRIVATE KEY」を持つPEMエンコードオブジェクトを取得します。


概要:「PKCS#1形式のECキー」などはありません。PKCS#1はRSAキー専用であり、ECキーではありません。ただし、PKCS#1に似ていますがECキー用に作成され、SEC 1で定義された別の形式があります。OpenSSLは、「openssl pkcs8」コマンドを使用してその形式を汎用PKCS#8に変換し、「」を使用してSEC 1形式に戻すことができます。 openssl ec」。

27
Thomas Pornin

ECキーをRSA PKCS#1キーに変換できますか?そして、もしそうなら、どうですか?

No。 RSAはECCとは関係ありません。

現在、一部の暗号には、通常バージョンとECバージョンの両方があります。
(例は、DH/ECDH、DSA/ECDSAです。)しかし、単に「ECRSA」などはありません。 RSAのみです。

0
StackzOfZtuff