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

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

问题描述

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

I have a private raw key of myetherwallet with a passphrase "testwallet", now I am trying to convert it to a PEM format using OpenSSL following this answer.

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:

更新:我没有公钥,而是想生成它,以便稍后我也可以生成对应的以太坊地址..

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

推荐答案

您声称您的原始密钥采用 OpenSSL 的 DER 格式,但事实并非如此.此外,您声称私钥是公钥,但事实并非如此,并声称它是密码加密的,无论哪种方式都是错误的:公钥从未加密,而 OpenSSL 的传统"又名传统"算法中的私钥是特定的DER 格式(对于 ECC,由 SECG SEC1 定义)无法加密.(PKCS8 格式的 OTOH 私钥可以在 DER 或 PEM 中进行密码加密,尽管 PEM 更方便.而 FWIW PKCS12 格式始终是密码加密的,并且始终是 DER.)

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.)

ECC(ECDSA、ECDH、ECMQV 等)键总是相对于某个曲线"(更准确地说,是曲线上的质数阶子群,具有确定的生成器,即基点).对于比特币,这是 secp256k1,但您的问题并没有说它仅限于比特币,并且此答案需要针对使用其他曲线的其他应用程序进行修改.

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.

如果您还有公钥(作为未压缩点),您可以简单地使用 https://bitcoin.stackexchange.com/questions/66594/signing-transaction-with-ssl-private-key-to-pem.连接十六进制字符串:

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)

然后将十六进制转换为二进制并读取为 DER,或将十六进制(可能通过二进制)转换为 base64 并用 -----BEGIN/END EC PRIVATE KEY-- 行使其成为 PEM.

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 

并转换为二进制,然后读入 openssl ec -inform d .注意 OpenSSL 将从给定曲线的私钥派生公钥,但实际上并不将其存储在 PEM 输出中,因此不能保证使用 OpenSSL 以外的软件进行读取.您可能需要使用 openssl ec -text [-noout](在 PEM 或 DER 输入上方便)来获取公钥值,然后返回并创建包含公钥的更完整的编码如上.

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.

a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 是以十六进制表示的原始私钥.secp256k1 私有值是 32 字节的二进制;当二进制以十六进制表示时,每个字节需要两个十六进制数字,因此 32 个字节需要 64 个十六进制数字.所有这些值都是原始私钥.没有任何由 25 个数字或 25 个字节组成的部分具有任何有用的意义.请勿使用此值的任何 25-任何部分.

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.

要构造没有公钥的私钥的 OpenSSL/SECG 表示,请将表示私钥的十六进制字符串——所有这些字符串,未经修改——放在另外两个十六进制字符串之间我显示为第二个选项:

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 

然后将这个组合的十六进制字符串转换为二进制,并将结果读入openssl ec -inform d:

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

结果是 PEM 格式——但 PEM 格式不包括您指定的公钥.要查看包含派生公钥的字段,请添加 -text;要仅查看字段而不查看 PEM 输出,请添加 -noout:

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

现在,如果您想要一个 PEM 格式的密钥包括公钥,请两者获取私钥的十六进制字符串(所有 64 位数字)和新显示的公钥的十六进制值,并将它们插入我的第一个选项.另请注意,ECC 公钥是一个曲线点,它可以有两种形式,压缩或未压缩;此处生成的表格未压缩.如果您需要压缩,我稍后会添加.未压缩形式的 secp256k1 点为 65 个字节,以十六进制表示为 130 个十六进制数字.(其中 openssl ec 格式化为 4 行,每行 15 个字节,剩下 5 个字节.)

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

<小时>

为 DavidS 添加了 2019-02:如k06a 的答案

  • 我的中字符串的第一部分(或我的私人选项的整个后缀)a00706052b8104000a 是一个上下文标签和长度 a007 用于 OID标签和长度 0605 包含 2b8104000a,即 1.3.132.0.10 即 secp256k1

  • 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

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

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.

要改为执行 secp256r1 又名 P-256 或 prime256v1,您需要将 AlgId.OID 更改为 1.2.840.10045.3.1.7 编码为 a00a 0608 2a8648ce3d030107.p256r1 的私钥和公钥值与 p256k1 的大小相同,但 AlgId 更长,因此您还需要更改外部 SEQUENCE 的长度,给出

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天全站免登陆