如何将ECDSA密钥转换为PEM格式 [英] How to convert an ECDSA key to PEM format

查看:826
本文介绍了如何将ECDSA密钥转换为PEM格式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 myetherwallet 的私有原始密钥,并带有一个 passphrase "testwallet",现在我正按照此答案尝试使用OpenSSL将其转换为PEM格式. /p>

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:

更新: 我没有公钥,相反,我想生成它,因此以后我还可以生成对应的以太坊地址..

解决方案

您声称您的原始密钥采用OpenSSL的DER格式,并非如此.另外,您还声称私有密钥不是公共密钥,而是声称它是用密码加密的,无论哪种方式都是错误的:公共密钥从不加密,私有密钥在OpenSSL的传统"(也称为旧版")算法中无法加密DER格式(对于ECC,由 SECG SEC1 定义). (虽然PEM更加方便,但可以使用DER或PEM对PKCS8格式的OTOH私钥进行密码加密.并且FWIW PKCS12格式始终对密码进行加密,并且始终对DER.)

ECC(ECDSA,ECDH,ECMQV等)键始终相对于某些曲线"(更确切地说,是具有已标识的生成器即基点的曲线的素数子组).对于比特币,这是 secp256k1 ,但是您的问题并不只限于比特币,而这个答案可能需要使用其他曲线的其他应用程序进行修改.

如果您还具有公共密钥(作为未压缩的点),则可以简单地使用 k06a的答案

中正确显示
  • 我的中间字符串的第一部分(或我的仅供私人使用的选项的整个后缀)a00706052b8104000a是上下文标记,长度为a007,是OID标记,长度为0605,其中包含2b8104000a这是 1.3.132.0.10,即secp256k1

  • 我的中间字符串a144034200的其余部分是上下文标记和长度,其中包含标记长度和BITSTRING的未使用位头,BITSTRING是未压缩的原始公钥.

要改为使用 secp256r1 aka P-256或prime256v1,则需要将AlgId.OID更改为

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

But this error appears:

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:

UPDATE: I don't have the public key, instead I want to generate it so later I can also generate the Ethereum address corresponds..

You are claiming your raw key is in OpenSSL's DER format, which it isn't. Also you are claming a private key is a public key, which it isn't, and claiming it's password-encrypted which is wrong either way: public keys are never encrypted and private keys in OpenSSL's 'traditional' aka 'legacy' algorithm-specific DER formats (for ECC, defined by SECG SEC1) cannot be encrypted. (OTOH private keys in PKCS8 format can be password-encrypted in either DER or PEM, although PEM is more convenient. And FWIW PKCS12 format is always password-encrypted, and always DER.)

An ECC (ECDSA, ECDH, ECMQV, etc) key is always relative to some 'curve' (more exactly, prime-order subgroup over a curve with an identified generator aka base point). For bitcoin this is secp256k1, but your question doesn't say it's limited to bitcoin and this answer would require modification for other applications using other curves.

If you also have the public key (as an uncompressed point), you can simply use the solution from https://bitcoin.stackexchange.com/questions/66594/signing-transaction-with-ssl-private-key-to-pem . Concatenate the hex strings:

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

and then either convert the hex to binary and read as DER, or convert the hex (probably via binary) to base64 and wrap with -----BEGIN/END EC PRIVATE KEY----- lines to make it PEM.

If you don't have the public key, you can modify this slightly. Concatenate the hex strings

302e0201010420 privkey_32bytes_64hexits a00706052b8104000a 

and convert to binary, then read into openssl ec -inform d . Note OpenSSL will derive the public key from the private key given the curve, but not actually store it in the PEM output, so reading with software other than OpenSSL is not guaranteed. You might need to use openssl ec -text [-noout] (on either PEM or DER input as convenient) to get the public key value, then go back and create the fuller encoding that includes the public key as above.


ADDED: since you seem not to comprehend the words in the answer, I'll lay this out in as much detail as I can.

The value a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 is the raw private key represented in hex. A secp256k1 private value is 32 bytes in binary; when binary is represented in hex each byte takes two hex digits, so 32 bytes takes 64 hex digits. All of this value is the raw private key. There is no part consisting of 25 digits OR 25 bytes that has any useful meaning whatever. Do not take any 25-anything part of this value.

To construct the OpenSSL/SECG representation of a private key with no public key, put the hex string representing the private key -- all of it, without modification -- between the two other hex strings I showed as the second option:

 302e0201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000a 

Then convert this combined hex string to binary, and read the result into 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-----

The result is PEM format -- but PEM format not including the public key, which you indicate you want. To see the fields including the derived public key, add -text; to see only the fields and not the PEM output, add -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

Now if you want a PEM-format key including the public key, take both the hex strings for the private key (all 64 digits) AND the newly-shown hex value for the public key, and plug them in to my first option. Also note an ECC public key is a curve point which can be in two forms, compressed or uncompressed; the form generated here is uncompressed. If you need compressed, I'll add that later. A secp256k1 point in uncompressed form is 65 bytes, represented in hex as 130 hex digits. (Which openssl ec formats as 4 lines each of 15 bytes with 5 bytes left over.)

$ 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-----


ADDED 2019-02 for DavidS: as correctly shown in k06a's answer

  • the first part of my midstring (or the entire suffix for my private-only option) a00706052b8104000a is a context-tag and length a007 for an OID tag and length 0605 containing 2b8104000a which is 1.3.132.0.10 which is secp256k1 and

  • the remainder of my midstring a144034200 is a context tag and length containing the tag length and unused-bits header for a BITSTRING which is the raw publickey as an uncompressed point.

To do secp256r1 aka P-256 or prime256v1 instead, you need to change the AlgId.OID to 1.2.840.10045.3.1.7 which is encoded as a00a 0608 2a8648ce3d030107. The privatekey and publickey values for p256r1 are the same sizes as for p256k1, but the AlgId is longer, so you also need to change the length of the outer SEQUENCE giving

30770201010420 privatekey32bytes # note 77 
a00a06082a8648ce3d030107 a144034200 publicpoint65bytes 

这篇关于如何将ECDSA密钥转换为PEM格式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆