如何将 ECDSA 密钥转换为 PEM 格式

2024-02-03

我有一个私人原始密钥米以太钱包 with a 密码短语“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:

UPDATE:我没有公钥,而是想生成它,以便稍后我还可以生成对应的以太坊地址。


您声称您的原始密钥采用 OpenSSL 的 DER 格式,但事实并非如此。此外,您还声称私钥是公钥,但事实并非如此,并声称它是密码加密的,无论哪种方式都是错误的:公钥从未加密,而 OpenSSL 的“传统”又名“遗留”算法特定的私钥DER 格式(对于 ECC,定义为SECG SEC1 https://www.secg.org) 无法加密。 (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 https://bitcoin.stackexchange.com/questions/66594/signing-transaction-with-ssl-private-key-to-pem。连接十六进制字符串:

  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。

如果您没有公钥,你可以稍微修改一下。连接十六进制字符串

302e0201010420 privkey_32bytes_64hexits a00706052b8104000a 

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


ADDED:由于您似乎不理解答案中的词语,因此我将尽可能详细地阐述这一点。

价值a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57是以十六进制表示的原始私钥。 secp256k1 私有值是 32 个二进制字节;当二进制以十六进制表示时,每个字节需要两个十六进制数字,因此 32 个字节需要 64 个十六进制数字。所有这些值都是原始私钥。由 25 位数字或 25 个字节组成的部分没有任何任何有用的含义。不要取该值的任何 25 部分。

构建 OpenSSL/SECG 表示没有公钥的私钥,将代表私钥的十六进制字符串(全部,无需修改)放在我作为第二个选项显示的其他两个十六进制字符串之间:

 302e0201010420 a140bd507a57360e2fa503298c035854f0dcb248bedabbe7a14db3920aaacf57 a00706052b8104000a 

然后将这个组合的十六进制字符串转换为二进制,并将结果读入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 格式的密钥包括公钥, take both私钥的十六进制字符串(全部 64 位)和公钥的新显示的十六进制值,并将它们插入到我的first选项。另请注意,ECC 公钥是一个曲线点,可以有两种形式:压缩或未压缩;此处生成的表单未压缩。如果您需要压缩,我稍后会添加。未压缩形式的 secp256k1 点为 65 个字节,以十六进制表示为 130 个十六进制数字。 (哪个openssl ec格式为 4 行,每行 15 个字节,剩余 5 个字节。)

$ 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 的回答 https://stackoverflow.com/a/49213805

  • 我的中弦的第一部分(或我的私人选项的整个后缀)a00706052b8104000a是上下文标签和长度a007用于 OID 标签和长度0605含有2b8104000a这是1.3.132.0.10 即 secp256k1 http://www.oid-info.com/get/1.3.132.0.10 and

  • 我的中弦的其余部分a144034200是上下文标记和长度,包含 BITSTRING 的标记长度和未使用位标头,BITSTRING 是作为未压缩点的原始公钥。

To do secp256r1又名 P-256 或 prime256v1,您需要将 AlgId.OID 更改为1.2.840.10045.3.1.7 http://www.oid-info.com/get/1.2.840.10045.3.1.7编码为a00a 0608 2a8648ce3d030107。 p256r1 的私钥和公钥值与 p256k1 的大小相同,但 AlgId 更长,因此您还需要更改外部 SEQUENCE 的长度

30770201010420 privatekey32bytes # note 77 
a00a06082a8648ce3d030107 a144034200 publicpoint65bytes 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 ECDSA 密钥转换为 PEM 格式 的相关文章

随机推荐