您声称您的原始密钥在OpenSSL的DER格式中,但实际上并不是。此外,您声称一个私钥是公钥,但事实并非如此,并声称它是密码加密的,这两种说法都是错误的:公钥从不被加密,而在OpenSSL的“传统”算法特定DER格式(对于ECC,在
SECG SEC1中定义)中,私钥不能加密。 (另一方面,在PKCS8格式中的私钥可以使用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中的解决方案。将十六进制字符串连接起来:
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输入上都可以方便地执行)来获取公钥值,然后返回并创建包括公钥在内的更完整的编码。
添加:由于您似乎无法理解答案中的单词,我将尽可能详细地说明这一点。
值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 格式,但不包括公钥,而您需要公钥。要查看包括派生公钥的字段,请添加
-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格式密钥,需要将私钥的十六进制字符串(所有64个数字)和新显示的公钥的十六进制值一起,输入到我的第一个选项中。请注意,ECC公钥是一个曲线点,可以采用压缩或未压缩两种形式,此处生成的是未压缩的形式。如果您需要压缩形式,我稍后会添加。一个未压缩的secp256k1点是65个字节,以十六进制表示为130个十六进制数字。(openssl ec
将其格式化为每行15个字节的4行,剩下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
$
$ 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: 根据 k06a的回答,我的midstring(或仅供私人使用的选项的整个后缀)的第一部分a00706052b8104000a
是上下文标签和长度a007
,用于OID标记和长度0605
,其中包含1.3.132.0.10,即secp256k1,而我的midstring的其余部分a144034200
是一个上下文标签和长度,其中包含BITSTRING的标记长度和未使用位头,作为未压缩点的原始公钥。
要改用secp256r1或P-256或prime256v1,您需要将AlgId.OID更改为1.2.840.10045.3.1.7,它被编码为a00a06082a8648ce3d030107
。 p256r1的私钥和公钥值与p256k1相同,但AlgId较长,因此您还需要更改外部SEQUENCE的长度。
30770201010420 privatekey32bytes
a00a06082a8648ce3d030107 a144034200 publicpoint65bytes
a00706052b8104000aa144034200
的?我需要同样的东西,但是针对 secp256r1。 - DavidS