问题描述
有没有办法从 EC PKCS#8 中提取原始/八位字节私钥?
-----BEGIN PRIVATE KEY-----
MIH3AgEAMBAGByqGSM49AgEGBSuBBAAjBIHfMIHcAgEBBEIA1tZ6QFxLWMJyp7vO
pDNj2Wbu2or9QaxJ3ehpi1qaVF/otjrx3Q/AMso4W9a6YQ4heDCH1rned0C2VdyK
f8n0bcugBwYFK4EEACOhgYkDgYYABAGi+uY7a67sTbwOAK/+aNUewZ3haLUV4INx
Fnk6E1iNee0YvyQ5XJrowSWjW6YfBTjYKKKYeaV5s2QTbzhvgvqL3gD1EgXNbfB9
27lO2Luy0EYxOPLxtBhCEgGnlkzHVwZaKK3+qJpR+D6oVe7l0hgBfoIYzkJgpQPC
1lblIG8qAtQEGg==
-----END PRIVATE KEY-----
如果我跑:
# openssl ec -in private.pem -text -noout
我得到:
read EC key
Private-Key: (521 bit)
priv:
00:d6:d6:7a:40:5c:4b:58:c2:72:a7:bb:ce:a4:33:
63:d9:66:ee:da:8a:fd:41:ac:49:dd:e8:69:8b:5a:
9a:54:5f:e8:b6:3a:f1:dd:0f:c0:32:ca:38:5b:d6:
ba:61:0e:21:78:30:87:d6:b9:de:77:40:b6:55:dc:
8a:7f:c9:f4:6d:cb
pub:
04:01:a2:fa:e6:3b:6b:ae:ec:4d:bc:0e:00:af:fe:
68:d5:1e:c1:9d:e1:68:b5:15:e0:83:71:16:79:3a:
13:58:8d:79:ed:18:bf:24:39:5c:9a:e8:c1:25:a3:
5b:a6:1f:05:38:d8:28:a2:98:79:a5:79:b3:64:13:
6f:38:6f:82:fa:8b:de:00:f5:12:05:cd:6d:f0:7d:
db:b9:4e:d8:bb:b2:d0:46:31:38:f2:f1:b4:18:42:
12:01:a7:96:4c:c7:57:06:5a:28:ad:fe:a8:9a:51:
f8:3e:a8:55:ee:e5:d2:18:01:7e:82:18:ce:42:60:
a5:03:c2:d6:56:e5:20:6f:2a:02:d4:04:1a
ASN1 OID: secp521r1
NIST CURVE: P-521
我需要“PRIV”值以二进制格式或至少为十六进制的字符串:。的 00d6d67a405c4b58c272a7bbcea43363d966eeda8afd41ac49dde8698b5a9a545fe8b63af1dd0fc032ca385bd6ba610e21783087d6b9de7740b655dc8a7fc9f46dcb 这样就可以与XXD将其转换为二进制
我该怎么做?
我总是可以做这样的事情:
openssl ec -in private.pem -text -noout | tr '\n' ' ' | grep -Po '(?<=priv:).*(?=pub:)' | tr -cd '[0-9a-f]'
但这是一种糟糕的方法,恕我直言。
解决方法
仍然不漂亮,但可以使用 asn1parse
来替代您的解决方案。检查整个密钥文件的输出:
$ openssl asn1parse -in private.pem
0:d=0 hl=3 l= 247 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :00
6:d=1 hl=2 l= 16 cons: SEQUENCE
8:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
17:d=2 hl=2 l= 5 prim: OBJECT :secp521r1
24:d=1 hl=3 l= 223 prim: OCTET STRING [HEX DUMP]:3081DC020101044200D6D67A405C4B58C272A7BBCEA43363D966EEDA8AFD41AC49DDE8698B5A9A545FE8B63AF1DD0FC032CA385BD6BA610E21783087D6B9DE7740B655DC8A7FC9F46DCBA00706052B81040023A18189038186000401A2FAE63B6BAEEC4DBC0E00AFFE68D51EC19DE168B515E0837116793A13588D79ED18BF24395C9AE8C125A35BA61F0538D828A29879A579B364136F386F82FA8BDE00F51205CD6DF07DDBB94ED8BBB2D0463138F2F1B418421201A7964CC757065A28ADFEA89A51F83EA855EEE5D218017E8218CE4260A503C2D656E5206F2A02D4041A
实际的密钥(对)信息从偏移量 24
开始,它是一个八位字节字符串,它本身就是一个 ASN.1 对象。放大到该位置:
$ openssl asn1parse -in private.pem -strparse 24
0:d=0 hl=3 l= 220 cons: SEQUENCE
3:d=1 hl=2 l= 1 prim: INTEGER :01
6:d=1 hl=2 l= 66 prim: OCTET STRING [HEX DUMP]:00D6D67A405C4B58C272A7BBCEA43363D966EEDA8AFD41AC49DDE8698B5A9A545FE8B63AF1DD0FC032CA385BD6BA610E21783087D6B9DE7740B655DC8A7FC9F46DCB
74:d=1 hl=2 l= 7 cons: cont [ 0 ]
76:d=2 hl=2 l= 5 prim: OBJECT :secp521r1
83:d=1 hl=3 l= 137 cons: cont [ 1 ]
86:d=2 hl=3 l= 134 prim: BIT STRING
OCTET STRING
是私有组件,可以使用 awk
和 xxd
工具提取并转换为二进制文件,如下所示:
$ openssl asn1parse -in private.pem -strparse 24 | awk -F ":" '/OCTET STRING/ {print $4}' | xxd -r -p > private.der
在编写此初始方法后,我意识到 ec
工具与更简单的 ans1parse
调用相结合也同样有效:
$ openssl ec -in private.pem | openssl asn1parse | awk -F ":" '/OCTET STRING/ {print $4}' | xxd -r -p > private.der