OpenSSL生成的pem密钥是否与Erlang Crypto兼容

OpenSSL生成的pem密钥是否与Erlang Crypto兼容,openssl,cryptography,erlang,ecdsa,Openssl,Cryptography,Erlang,Ecdsa,我使用OpenSSL生成了一个私钥: ARWIN-TIO:/tmp$ openssl ecparam -name prime256v1 -genkey -noout -out key.pem ARWIN-TIO:/tmp$ cat key.pem -----BEGIN EC PRIVATE KEY----- MHcCAQEEIINcLTcsL/VhTBEsp1gRgHtO9lLzypm7oYjwViz3bWZCoAoGCCqGSM49 AwEHoUQDQgAE8kuZsfDhQdkkYjVRla

我使用OpenSSL生成了一个私钥:

ARWIN-TIO:/tmp$ openssl ecparam -name prime256v1 -genkey -noout -out key.pem
ARWIN-TIO:/tmp$ cat key.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIINcLTcsL/VhTBEsp1gRgHtO9lLzypm7oYjwViz3bWZCoAoGCCqGSM49
AwEHoUQDQgAE8kuZsfDhQdkkYjVRla3ShxAlsbLwOt8jUsKyebB7GGWxnBiDqRoB
bSxkkd+APIM/4+lYwIDAx5+EmIIuUIRdcA==
-----END EC PRIVATE KEY-----
我很难在Erlang的加密模块中使用它:

ARWIN-TIO:/tmp$ erl
Erlang/OTP 21 [erts-10.3.5.6] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.3.5.6  (abort with ^G)
1> Message = <<"Hello">>.
<<"Hello">>
2> PrivateKey = base64:decode("MHcCAQEEIINcLTcsL/VhTBEsp1gRgHtO9lLzypm7oYjwViz3bWZCoAoGCCqGSM49AwEHoUQDQgAE8kuZsfDhQdkkYjVRla3ShxAlsbLwOt8jUsKyebB7GGWxnBiDqRoBbSxkkd+APIM/4+lYwIDAx5+EmIIuUIRdcA==").
<<48,119,2,1,1,4,32,131,92,45,55,44,47,245,97,76,17,44,
  167,88,17,128,123,78,246,82,243,202,153,...>>
3> Signature = crypto:sign(ecdsa, sha256, Message, [PrivateKey, prime256v1]).
** exception error: badkey
     in function  crypto:sign/5
        called as crypto:sign(ecdsa,sha256,<<"Hello">>,
                              [<<48,119,2,1,1,4,32,131,92,45,55,44,47,245,97,76,17,44,
                                 167,88,17,128,123,78,...>>,
                               prime256v1],
                              [])
ARWIN-TIO:/tmp$erl
Erlang/OTP 21[erts-10.3.5.6][source][64位][smp:8:8][ds:8:8:10][async threads:1][hipe][dtrace]
Eshell V10.3.5.6(使用^G中止)
1> 消息=。
2> PrivateKey=base64:解码(“MHCCAQEEINCTCSL/VHTBESP1GRGHTO9LLZYPM7OYJWVIZ3BWZCOAGCCQGSM49WEQDQGAE8KUZSFDHQDKKYJVRLA3SHXALSBLWOT8JUSKYEBB7GGWXNBIDQROBBSXKKD+APIM/4+lYwIDAx5+EMIURDCA=”)。
3> 签名=加密:签名(ecdsa,sha256,消息,[PrivateKey,prime256v1])。
**异常错误:坏键
函数内加密:符号/5
称为加密:符号(ecdsa,sha256,,
[,
prime256v1],
[])
当我使用Erlang的加密模块生成密钥时,它可以工作:

ARWIN-TIO:/tmp$ erl
Erlang/OTP 21 [erts-10.3.5.6] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.3.5.6  (abort with ^G)
1> Message = <<"Hello">>.
<<"Hello">>
2> {PublicKey, PrivateKey} = crypto:generate_key(ecdh, crypto:ec_curve(prime256v1)).
{<<4,149,38,43,104,132,214,232,147,174,88,185,96,250,185,
   181,170,8,231,61,255,134,143,255,4,136,249,9,...>>,
 <<130,195,50,229,108,51,72,27,219,145,250,244,116,3,52,
   234,13,60,148,175,112,192,140,110,232,46,116,...>>}
3> Signature = crypto:sign(ecdsa, sha256, Message, [PrivateKey, prime256v1]).
<<48,70,2,33,0,252,243,117,254,110,176,232,185,121,156,93,
  105,74,115,115,247,83,82,17,32,167,254,223,74,...>>
ARWIN-TIO:/tmp$erl
Erlang/OTP 21[erts-10.3.5.6][source][64位][smp:8:8][ds:8:8:10][async threads:1][hipe][dtrace]
Eshell V10.3.5.6(使用^G中止)
1> 消息=。
2> {PublicKey,PrivateKey}=crypto:generate_key(ecdh,crypto:ec_曲线(prime256v1))。
{,
}
3> 签名=加密:签名(ecdsa,sha256,消息,[PrivateKey,prime256v1])。
我注意到Erlang私钥比OpenSSL私钥短得多:

4> base64:encode(PrivateKey).
<<"gsMy5WwzSBvbkfr0dAM06g08lK9wwIxu6C50rwKaBvw=">>
4>base64:encode(私钥)。
这比使用“openssl ecparam-name prime256v1-genkey-noout-out key.pem”生成的要短得多

为什么OpenSSL密钥与Erlang的加密模块不同/不起作用?如何使它们兼容


谢谢。

您现在看到的是一个X9.62编码的私钥,它还进行了PEM编码。您已经删除了PEM头行并解码了base 64,因此现在只剩下X9.62编码的私钥

由于您似乎正在使用OpenSSL,请首先解码base64,以便执行以下操作:

openssl asn1parse-notify DER-in private_prime256v1.bin
这将给你:

0:d=0 hl=2 l=119 cons:SEQUENCE
2:d=1 hl=2 l=1初始值:整数:01
5:d=1 hl=2 l=32初始值:八位字节字符串[十六进制转储]:
835C2D372C2F5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
39:d=1 hl=2 l=10 cons:cont[0]
41:d=2 hl=2 l=8原始:对象:原始256V1
51:d=1 hl=2 l=68 cons:cont[1]
53:d=2 hl=2 l=66原始:位字符串
您还没有清楚地显示公钥/私钥的完整扩展,但是看起来它们只是秘密S的“平面”表示,对于公钥,是未压缩点W

因此,这将是解析私钥中的八位字符串(最后的位字符串包含可选的公钥,未压缩的点W):

835C2D372C2FF5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
这就解释了原因。我不知道如何解析这样的结构,但您可能不必这样做。看起来Erlang已经有一个函数为您实现了这一点,名为
public\u key:pem\u decode
,它应该只获取整个
openssl
生成的密钥。根据该协议,它还应该解析私钥


因为我不是Erlang程序员,所以我无法轻松测试这一点,所以请告诉我。

您所看到的是一个X9.62编码的私钥,它还进行了PEM编码。您已经删除了PEM头行并解码了base 64,因此现在只剩下X9.62编码的私钥

由于您似乎正在使用OpenSSL,请首先解码base64,以便执行以下操作:

openssl asn1parse-notify DER-in private_prime256v1.bin
这将给你:

0:d=0 hl=2 l=119 cons:SEQUENCE
2:d=1 hl=2 l=1初始值:整数:01
5:d=1 hl=2 l=32初始值:八位字节字符串[十六进制转储]:
835C2D372C2F5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
39:d=1 hl=2 l=10 cons:cont[0]
41:d=2 hl=2 l=8原始:对象:原始256V1
51:d=1 hl=2 l=68 cons:cont[1]
53:d=2 hl=2 l=66原始:位字符串
您还没有清楚地显示公钥/私钥的完整扩展,但是看起来它们只是秘密S的“平面”表示,对于公钥,是未压缩点W

因此,这将是解析私钥中的八位字符串(最后的位字符串包含可选的公钥,未压缩的点W):

835C2D372C2FF5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
这就解释了原因。我不知道如何解析这样的结构,但您可能不必这样做。看起来Erlang已经有一个函数为您实现了这一点,名为
public\u key:pem\u decode
,它应该只获取整个
openssl
生成的密钥。根据该协议,它还应该解析私钥


由于我不是Erlang程序员,所以无法轻松测试,请告诉我。

在Maarten的指导下,我设法找到了答案(不知道我的OpenSSL私钥是“X9.62”编码的;我以为它只在base64中)。事实证明,您需要使用
公钥
模块,而不是
加密
模块

下面是一个如何使用带有Erlang的OpenSSL密钥的示例

生成私钥:

ARWIN-TIO:/tmp$ openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
ARWIN-TIO:/tmp$ cat private_key.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIGpSqNErkMHbjdeBQBI6NdlK8QgFluCJvGhkt3g5n5zboAoGCCqGSM49
AwEHoUQDQgAE43/FB66JPZ2JCbL+e7b4TVpDJAOeeaHmy7NPYL1cOVJFRBux91M4
QYBu1s5DigaQdi/Qz7KK/Yr5EMktgulXHA==
-----END EC PRIVATE KEY-----
以及相应的公钥:

ARWIN-TIO:/tmp$ openssl ec -in private_key.pem -pubout -out public_key.pub
ARWIN-TIO:/tmp$ cat public_key.pub
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE43/FB66JPZ2JCbL+e7b4TVpDJAOe
eaHmy7NPYL1cOVJFRBux91M4QYBu1s5DigaQdi/Qz7KK/Yr5EMktgulXHA==
-----END PUBLIC KEY-----
然后在Erlang中,您可以签署如下消息:

(2020-01-02 20:51:56) ARWIN-TIO:/tmp$ erl
Erlang/OTP 21 [erts-10.3.5.6] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.3.5.6  (abort with ^G)
1> Message = <<"My Secret Message">>,
1> 
1> PrivatePem = lists:nth(1, public_key:pem_decode(<<"-----BEGIN EC PRIVATE KEY-----
1> MHcCAQEEIGpSqNErkMHbjdeBQBI6NdlK8QgFluCJvGhkt3g5n5zboAoGCCqGSM49
1> AwEHoUQDQgAE43/FB66JPZ2JCbL+e7b4TVpDJAOeeaHmy7NPYL1cOVJFRBux91M4
1> QYBu1s5DigaQdi/Qz7KK/Yr5EMktgulXHA==
1> -----END EC PRIVATE KEY-----">>)),
1>
1> PrivateKey = public_key:pem_entry_decode(PrivatePem),
1> Signature = public_key:sign(Message, sha256, PrivateKey).
<<48,68,2,32,64,80,146,169,96,232,174,140,196,59,46,54,
  107,199,145,184,86,181,79,168,165,107,54,157,222,...>>
2> PublicPem = lists:nth(1, public_key:pem_decode(<<"-----BEGIN PUBLIC KEY-----
2> MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE43/FB66JPZ2JCbL+e7b4TVpDJAOe
2> eaHmy7NPYL1cOVJFRBux91M4QYBu1s5DigaQdi/Qz7KK/Yr5EMktgulXHA==
2> -----END PUBLIC KEY-----">>)),
2> 
2> PublicKey = public_key:pem_entry_decode(PublicPem),
2> VerifyResult = public_key:verify(Message, sha256, Signature, PublicKey),
2> VerifyResult.
true
(2020-01-02 20:51:56)ARWIN-TIO:/tmp$erl
Erlang/OTP 21[erts-10.3.5.6][source][64位][smp:8:8][ds:8:8:10][async threads:1][hipe][dtrace]
Eshell V10.3.5.6(使用^G中止)
1> 消息=,
1> 
1> PrivatePem=list:n(1,公钥:pem\u decode(>),
1>
1> 私钥=公钥:pem输入解码(私钥),
1> 签名=公钥:签名(消息,sha256,私钥)。
您可以这样进行验证:

(2020-01-02 20:51:56) ARWIN-TIO:/tmp$ erl
Erlang/OTP 21 [erts-10.3.5.6] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Eshell V10.3.5.6  (abort with ^G)
1> Message = <<"My Secret Message">>,
1> 
1> PrivatePem = lists:nth(1, public_key:pem_decode(<<"-----BEGIN EC PRIVATE KEY-----
1> MHcCAQEEIGpSqNErkMHbjdeBQBI6NdlK8QgFluCJvGhkt3g5n5zboAoGCCqGSM49
1> AwEHoUQDQgAE43/FB66JPZ2JCbL+e7b4TVpDJAOeeaHmy7NPYL1cOVJFRBux91M4
1> QYBu1s5DigaQdi/Qz7KK/Yr5EMktgulXHA==
1> -----END EC PRIVATE KEY-----">>)),
1>
1> PrivateKey = public_key:pem_entry_decode(PrivatePem),
1> Signature = public_key:sign(Message, sha256, PrivateKey).
<<48,68,2,32,64,80,146,169,96,232,174,140,196,59,46,54,
  107,199,145,184,86,181,79,168,165,107,54,157,222,...>>
2> PublicPem = lists:nth(1, public_key:pem_decode(<<"-----BEGIN PUBLIC KEY-----
2> MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE43/FB66JPZ2JCbL+e7b4TVpDJAOe
2> eaHmy7NPYL1cOVJFRBux91M4QYBu1s5DigaQdi/Qz7KK/Yr5EMktgulXHA==
2> -----END PUBLIC KEY-----">>)),
2> 
2> PublicKey = public_key:pem_entry_decode(PublicPem),
2> VerifyResult = public_key:verify(Message, sha256, Signature, PublicKey),
2> VerifyResult.
true
2>PublicPem=list:n(1,公钥: