使用 OpenSSL CLI 从 PKSC8 EC 中提取原始八位字节私钥

问题描述

有没有办法从 EC PKCS#8 中提取原始/八位字节私钥?

这是一个示例文件 (private.pem):

-----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 是私有组件,可以使用 awkxxd 工具提取并转换为二进制文件,如下所示:

$ 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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...