Openssl 命令行:如何获取十六进制 public 密钥、224 位曲线的 PEM?

Openssl command line: how to get PEM for a hex public key, 224 bit curve?

我迷失在 openssl 命令行选项的曲折迷宫中,看起来都很相似...

来自一家芯片公司的 public 数据表显示此 public 密钥用于 secp224r1 的芯片身份验证: 048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68 422B81EC20B65A66B5102A61596AF3379200599316A00A1410

我已经将它保存为 ascii-hex 和二进制文件。我找不到 openssl 魔法来将其变成 PEM public 密钥以进行签名验证。这些是我最好的失败尝试:

$ openssl ec -in key57.hex -pubin -inform der -pubout -outform pem
read EC key
unable to load Key
34359738384:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:crypto/asn1/asn1_lib.c:91:
34359738384:error:0D068066:asn1 encoding routines:asn1_check_tlen:bad object header:crypto/asn1/tasn_dec.c:1118:
34359738384:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:290:Type=X509_ALGOR
34359738384:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:627:Field=algor, Type=X509_PUBKEY
$ openssl ec -in key57.bin -pubin -inform der -pubout -outform pem
read EC key
unable to load Key
34359738384:error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long:crypto/asn1/asn1_lib.c:101:

密钥是 114 个十六进制数字,代表 56 个字节,前缀为 04。这种密钥格式的正确名称是什么,将其转换为可用于以下内容的格式的正确方法是什么: openssl dgst -sha1 -verify public.pem -signature signature.bin test.bin

public 密钥以未压缩格式给出:0x04 + +

适用于 OpenSSL 验证的 public 密钥格式是 X.509/SPKI。据我所知,OpenSSL 不能在这两种格式之间进行转换。但转换可以很容易地手动完成。

X509/SPKI格式最后包含未压缩的密钥,前面部分对于某条曲线是相同的,例如secp224r1:

304e301006072a8648ce3d020106052b81040021033a00 + <your uncompressed key 048a...1410>

然后将结果进行 Base64 编码(每 64 个字符后换行)并添加 X.509/SPKI 密钥的页眉和页脚:

-----BEGIN PUBLIC KEY-----
ME4wEAYHKoZIzj0CAQYFK4EEACEDOgAEips4CvLuG5jcQX/swmP4RJx2Jc7Ogtm5
FsmS2iCdaEIrgewgtlpmtRAqYVlq8zeSAFmTFqAKFBA=
-----END PUBLIC KEY-----

secp224r1 的特定序列可以通过使用 secp224r1 的任意 X.509/SPKI 密钥来确定(例如,从使用 OpenSSL 生成的密钥对)。

您可以在 ASN.1 解码器中验证密钥,例如在线 https://lapo.it/asn1js.

您的密钥只是一个普通的 ECPoint(请参阅 RFC5480 的第 2 节)。为了有用,您需要采用 SubjectPublicKeyInfo 格式。不幸的是,OpenSSL 命令行不能直接读取 ECPoint。你需要做一些操作才能让它变得可读。

首先将您的十六进制密钥转换为二进制:

$ xxd -r -p key.hex key.bin

接下来我们将为同一曲线生成另一个 public 密钥以用作模板:

$ openssl ecparam -name secp224r1 -genkey -noout -out tempkey.pem
$ openssl ec -in tempkey.pem -pubout -outform der -out temppub.der
read EC key
writing EC key

看看生成的输出是这样的:

$ hexdump -C temppub.der 
00000000  30 4e 30 10 06 07 2a 86  48 ce 3d 02 01 06 05 2b  |0N0...*.H.=....+|
00000010  81 04 00 21 03 3a 00 04  93 6c be bb be d9 45 23  |...!.:...l....E#|
00000020  96 f6 0c 93 d5 72 ab 33  b5 ea c6 df c4 ac 68 1b  |.....r.3......h.|
00000030  2c e8 10 8d 5f b1 b8 80  7d 54 70 5e 21 cd e6 c6  |,..._...}Tp^!...|
00000040  21 a4 a5 f0 7e 1a 32 9d  75 de 3d fa c3 be 58 b6  |!...~.2.u.=...X.|
00000050

此 public 密钥由 23 个字节的 header 组成,后跟 ECPoint 数据。

要构建您想要的密钥,我们可以使用 header 的相同前 23 个字节并将您的密钥附加到末尾:

$ head -c 23 temppub.der >public-header.der
$ cat public-header.der key.bin >publickey.der

这给了我们编码为 DER 的密钥。要将其作为 PEM,我们这样做:

$ openssl ec -in publickey.der -pubin -inform der -out publickey.pem -pubout
read EC key
writing EC key

你可以这样检查:

$ cat publickey.pem
-----BEGIN PUBLIC KEY-----
ME4wEAYHKoZIzj0CAQYFK4EEACEDOgAEips4CvLuG5jcQX/swmP4RJx2Jc7Ogtm5
FsmS2iCdaEIrgewgtlpmtRAqYVlq8zeSAFmTFqAKFBA=
-----END PUBLIC KEY-----
$ openssl ec -pubin -in publickey.pem -noout -text
read EC key
Public-Key: (224 bit)
pub:
    04:8a:9b:38:0a:f2:ee:1b:98:dc:41:7f:ec:c2:63:
    f8:44:9c:76:25:ce:ce:82:d9:b9:16:c9:92:da:20:
    9d:68:42:2b:81:ec:20:b6:5a:66:b5:10:2a:61:59:
    6a:f3:37:92:00:59:93:16:a0:0a:14:10
ASN1 OID: secp224r1
NIST CURVE: P-224