web-dev-qa-db-ja.com

ECDSAキーをPEM形式に変換する方法

myetherwalletpassphrase "testwallet"の秘密の未加工キーを持っていますが、この回答に従ってOpenSSLを使用してPEM形式に変換しようとしています。

echo "a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57" | xxd -r -p - | openssl ec -inform der -pubin -noout -passin pass:testwallet -text

しかし、このエラーが表示されます:

read EC key
unable to load Key
140084694296480:error:0D06B08E:asn1 encoding routines:ASN1_D2I_READ_BIO:not enough data:a_d2i_fp.c:247:

PDATE:公開鍵がないので、代わりに生成したいので、後でイーサリアムアドレスも生成できます。

7
H Aßdøµ

生の鍵がOpenSSLのDER形式であると主張していますが、そうではありません。また、あなたは秘密鍵を公開鍵であると主張していますが、それはそうではなく、パスワードで暗号化されていると主張しています。これはどちらの方法でも間違っています:公開鍵は決して​​暗号化されず、OpenSSLの「従来の」別名「レガシー」アルゴリズム固有の秘密鍵DER形式(ECCの場合、 SECG SEC1 で定義)は暗号化できません。 (PKCS8形式のOTOH秘密鍵は、DERまたはPEMでパスワード暗号化できますが、PEMの方が便利です。また、FWIW PKCS12形式は常にパスワードで暗号化され、常にDERです。)

ECC(ECDSA、ECDH、ECMQVなど)のキーは常に /に関連します。いくつかの「曲線」(より正確には、特定されたジェネレーター、つまりベースポイントを持つ曲線上の素数サブグループ) 。ビットコインの場合、これは secp256k1 ですが、あなたの質問はそれがビットコインに限定されているとは言っていません。この回答は、他の曲線を使用する他のアプリケーションの変更を必要とします。

公開鍵(非圧縮ポイントとして)も持っている場合は、 https://bitcoin.stackexchange.com/questions/66594/のソリューションを使用できます。 signing-transaction-with-ssl-private-key-to-pem 。 16進文字列を連結します。

  a pre_string : 30740201010420
  the privkey  : (32 bytes as 64 hexits) 
  a mid_string : a00706052b8104000aa144034200 (identifies secp256k1) 
  the pubkey   : (65 bytes as 130 hexits)

次に、16進数をバイナリに変換してDERとして読み取るか、16進数(おそらくバイナリを介して)をbase64に変換し、-----BEGIN/END EC PRIVATE KEY-----行でラップしてPEMにします。

公開キーがない場合は、これを少し変更できます。 16進文字列を連結する

302e0201010420 privkey_32bytes_64hexits a00706052b8104000a 

バイナリに変換してから、openssl ec -inform dに読み込みます。注OpenSSLは、曲線が与えられた秘密鍵から公開鍵を導出しますが、実際にはPEM出力に格納しないため、OpenSSL以外のソフトウェアでの読み取りは保証されません。公開鍵の値を取得するためにopenssl ec -text [-noout](PEMまたはDER入力のいずれかで便利)を使用し、戻って上記の公開鍵を含む完全なエンコードを作成する必要がある場合があります。


ADDED:答えの単語を理解していないようですので、できるだけ詳しく説明します。

a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57は、16進数で表される未加工の秘密鍵です。 secp256k1プライベート値はバイナリで32バイトです。バイナリが16進数で表される場合、各バイトは2桁の16進数を使用するため、32バイトは64桁の16進数を使用します。この値はすべて未加工の秘密鍵です。 25桁の数字からなる部分はありませんOR 25バイトで、どんな意味でも役立ちます。この値の25の部分は取りません。

秘密鍵のOpenSSL/SECG表現を構築するには、公開鍵なしで、秘密鍵を表す16進文字列をすべて他の2つの16進数の間に入れます。 2番目のオプションとして示した文字列:

 302e0201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000a 

次に、この結合された16進文字列をバイナリに変換し、結果をopenssl ec -inform dに読み取ります。

$ echo 302e0201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000a | xxd -r -p >48101258.1
$ openssl ec -inform d <48101258.1
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIKFAvVB6VzYOL6UDKYwDWFTw3LJIvtq756FNs5IKqs9XoAcGBSuBBAAK
-----END EC PRIVATE KEY-----

結果はPEM形式ですが、PEM形式には公開キーが含まれていないため、ユーザーが希望する形式を選択できます。派生した公開鍵を含むフィールドを表示するには、-textを追加します。 PEM出力ではなくフィールドのみを表示するには、-nooutを追加します。

$ openssl ec -inform d <48101258.1 -text -noout
read EC key
Private-Key: (256 bit)
priv:
    a1:40:bd:50:7a:57:36:0e:2f:a5:03:29:8c:03:58:
    54:f0:dc:b2:48:be:da:bb:e7:a1:4d:b3:92:0a:aa:
    cf:57
pub:
    04:20:ea:6d:8c:e7:bc:bb:48:33:69:b2:91:1c:75:
    e5:60:2a:34:28:be:44:96:e9:7f:14:ad:52:fd:4a:
    6a:a0:e3:60:83:9c:6e:db:32:2a:22:55:7c:70:1e:
    d0:fa:1e:06:cf:57:4f:be:17:bd:6a:85:51:69:c5:
    65:96:72:cf:a9
ASN1 OID: secp256k1

PEM形式のキーが必要な場合公開キーを含め、both秘密キーの16進文字列(すべて64桁) )公開鍵の新しく表示された16進値のAND演算を行い、それらをmyfirstオプションに接続します。また、ECC公開鍵は、圧縮または非圧縮の2つの形式の曲線ポイントであることに注意してください。ここで生成されたフォームは圧縮されていません。圧縮が必要な場合は、後で追加します。非圧縮形式のsecp256k1ポイントは65バイトで、16進数で130桁の16進数として表されます。 (どのopenssl ecは、5バイトが残った15バイトの4行としてフォーマットされます。)

$ echo 30740201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000aa144034200 \
> 04:20:ea:6d:8c:e7:bc:bb:48:33:69:b2:91:1c:75: e5:60:2a:34:28:be:44:96:e9:7f:14:ad:52:fd:4a: \
> 6a:a0:e3:60:83:9c:6e:db:32:2a:22:55:7c:70:1e: d0:fa:1e:06:cf:57:4f:be:17:bd:6a:85:51:69:c5: \
> 65:96:72:cf:a9 | xxd -r -p >48101258.2
$ # note xxd -r -p ignores the colons; other hex programs may need them removed instead
$ openssl ec -inform d <48101258.2
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIKFAvVB6VzYOL6UDKYwDWFTw3LJIvtq756FNs5IKqs9XoAcGBSuBBAAK
oUQDQgAEIOptjOe8u0gzabKRHHXlYCo0KL5Elul/FK1S/UpqoONgg5xu2zIqIlV8
cB7Q+h4Gz1dPvhe9aoVRacVllnLPqQ==
-----END EC PRIVATE KEY-----

DavidSに2019-02を追加:正しく表示される k06aの回答

  • 中文字列の最初の部分(またはプライベートのみのオプションのサフィックス全体)a00706052b8104000aは、OIDタグと長さa007を含む0605のコンテキストタグと長さ2b8104000aです secp256k1である1.3.132.0.1 および

  • 私の中文字列a144034200の残りの部分は、コンテキストタグであり、非圧縮ポイントとしての生の公開鍵であるBITSTRINGのタグ長と未使用ビットヘッダーを含む長さです。

代わりに secp256r1 別名P-256またはprime256v1を実行するには、AlgId.OIDを 1.2.840.10045.3.1.7 に変更する必要があります。これはa00a 0608 2a8648ce3d030107としてエンコードされます。 p256r1のprivatekey値とpublickey値はp256k1のサイズと同じですが、AlgIdが長いため、外側のSEQUENCEの長さを変更する必要があります。

30770201010420 privatekey32bytes # note 77 
a00a06082a8648ce3d030107 a144034200 publicpoint65bytes 
13

楕円曲線秘密鍵の形式

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

したがって、publicKeyOPTIONALであり、理論的には見落とされる可能性があります。

これが私のDER secp256k1秘密鍵の例です。

30740201 01042092 E768CB72 0DC16924 27D156DB 39630748 0D1507B9 A4958450
2574B9A0 922F4BA0 0706052B 8104000A A1440342 00041954 9737B704 D1789A57
82E3430E 8259F904 71326081 054854D2 A5D096F9 686D05B0 30D98BA3 C60C056E
204CEF61 C0AC5B53 A9A6B9A0 5AFF9DA2 6CA4B65B 2E84

分解しようとしています:

$ openssl asn1parse -inform DER -in <(echo "30740201 01042092 E768CB72 0DC16924 27D156DB 39630748 0D1507B9 A4958450 2574B9A0 922F4BA0 0706052B 8104000A A1440342 00041954 9737B704 D1789A57 82E3430E 8259F904 71326081 054854D2 A5D096F9 686D05B0 30D98BA3 C60C056E 204CEF61 C0AC5B53 A9A6B9A0 5AFF9DA2 6CA4B65B 2E84" | xxd -r -p)

ASN.1解析結果:

 0:d=0  hl=2 l= 116 cons: SEQUENCE          
 2:d=1  hl=2 l=   1 prim: INTEGER           :01
 5:d=1  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:92E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4B
39:d=1  hl=2 l=   7 cons: cont [ 0 ]        
41:d=2  hl=2 l=   5 prim: OBJECT            :secp256k1
48:d=1  hl=2 l=  68 cons: cont [ 1 ]        
50:d=2  hl=2 l=  66 prim: BIT STRING  

詳細( https://bitcoin.stackexchange.com/a/66622/22979 を参照):

30 - ASN.1
74 - Length of all following bytes (116 bytes)

  02 - Type (integer)
  01 - Length of integer (1 byte)
  01 - Value of integer (1)

  04 - Type (octet string)
  20 - Length of string (32 bytes)
  92E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4B - Private Key

  A0 - Tag 0
  07 - Length of tag (7 bytes)
  06 - Type (Object ID)
  05 - Length of the Object ID (5 bytes)
  2b 81 04 00 0a - The object ID of the curve secp256k1

  A1 - Tag 1
  44 - Length of tag (68 bytes)
  03 - Type – Bit string
  42 - Length of the bit string (66 bytes)
  00 - ???
  04 - Uncompressed Public Key
  19549737B704D1789A5782E3430E8259F90471326081054854D2A5D096F9686D - Public Key X coord
  05B030D98BA3C60C056E204CEF61C0AC5B53A9A6B9A05AFF9DA26CA4B65B2E84 - Public Key Y coord

公開鍵オブジェクトを削除し、ASN.1の長さを116バイト(0x74)から46バイト(0x2e)に修正しました。

$ openssl asn1parse -inform DER -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

結果を得た:

 0:d=0  hl=2 l=  46 cons: SEQUENCE          
 2:d=1  hl=2 l=   1 prim: INTEGER           :01
 5:d=1  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:92E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4B
39:d=1  hl=2 l=   7 cons: cont [ 0 ]        
41:d=2  hl=2 l=   5 prim: OBJECT            :secp256k1

公開鍵を取得しようとしています:

$ openssl ec -inform DER -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

結果:

read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MC4CAQEEIJLnaMtyDcFpJCfRVts5YwdIDRUHuaSVhFAldLmgki9LoAcGBSuBBAAK
-----END EC PRIVATE KEY-----

もう一回試してみる:

$ openssl ec -inform DER -text -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

結果:

read EC key
Segmentation fault: 11

OSXシステムを使用しましたopensslLibreSSL 2.2.7

追加:LibreSSLにバグを報告しました: https://github.com/libressl-portable/portable/issues/395UPDATE:最新のmacOS 10.15.1にプリインストールされているopenssl(LibreSSL 2.8.3)では、このバグが修正されています。

次に、最新のopensslをインストールしました:brew install openssl

/usr/local/Cellar/openssl/1.0.2n/bin/openssl ec -inform DER -text -noout -in <(echo "302E020101042092E768CB720DC1692427D156DB396307480D1507B9A49584502574B9A0922F4BA00706052B8104000A" | xxd -r -p)

そして得た:

read EC key
Private-Key: (256 bit)
priv:
    00:92:e7:68:cb:72:0d:c1:69:24:27:d1:56:db:39:
    63:07:48:0d:15:07:b9:a4:95:84:50:25:74:b9:a0:
    92:2f:4b
pub: 
    04:19:54:97:37:b7:04:d1:78:9a:57:82:e3:43:0e:
    82:59:f9:04:71:32:60:81:05:48:54:d2:a5:d0:96:
    f9:68:6d:05:b0:30:d9:8b:a3:c6:0c:05:6e:20:4c:
    ef:61:c0:ac:5b:53:a9:a6:b9:a0:5a:ff:9d:a2:6c:
    a4:b6:5b:2e:84
ASN1 OID: secp256k1

最終的解決:

$ /usr/local/Cellar/openssl/1.0.2n/bin/openssl ec -inform DER -text -noout -in <(cat <(echo -n "302e0201010420") <(echo -n "***") <(echo -n "a00706052b8104000a") | xxd -r -p) 2>/dev/null | tail -6 | head -5 | sed 's/[ :]//g' | tr -d '\n' && echo

置換*** 16進数の秘密鍵を使用します。

2
k06a