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

时间:2020-01-01 11:49:15

标签: 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
AwEHoUQDQgAE8kuZsfDhQdkkYjVRla3ShxAlsbLwOt8jUsKyebB7GGWxnBiDqRoB
bSxkkd+APIM/4+lYwIDAx5+EmIIuUIRdcA==
-----END EC PRIVATE KEY-----

我正在努力在Erlang的Crypto模块中使用它:

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],
                              [])

当我使用Erlang的Crypto模块生成密钥时,它会起作用:

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,...>>

我注意到Erlang私钥比OpenSSL私钥短得多:

4> base64:encode(PrivateKey).
<<"gsMy5WwzSBvbkfr0dAM06g08lK9wwIxu6C50rwKaBvw=">>

比“ openssl ecparam -name prime256v1 -genkey -noout -out key.pem”生成的结果短得多。

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

谢谢。

2 个答案:

答案 0 :(得分:3)

您正在寻找的是X9.62编码的私钥,该私钥另外还进行了PEM编码。您已经删除了PEM标头行并解码了以64为基数的代码,因此现在只剩下X9.62编码的私钥。

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

openssl asn1parse -inform DER -in private_prime256v1.bin

哪个会给你:

     0:d=0  hl=2 l= 119 cons: SEQUENCE          
     2:d=1  hl=2 l=   1 prim: INTEGER           :01
     5:d=1  hl=2 l=  32 prim: OCTET STRING      [HEX DUMP]:
        835C2D372C2FF5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
    39:d=1  hl=2 l=  10 cons: cont [ 0 ]        
    41:d=2  hl=2 l=   8 prim: OBJECT            :prime256v1
    51:d=1  hl=2 l=  68 cons: cont [ 1 ]        
    53:d=2  hl=2 l=  66 prim: BIT STRING        

您还没有清楚地显示出公钥/私钥的完整范围,但是看起来它们只是秘密S的“平面”表示形式,对于公钥而言,它只是未压缩的点W。

因此,它将是已解析的私钥中的OCTET STRING(最后的BIT STRING包含可选的公钥,即未压缩的点W):

835C2D372C2FF5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642

所以这解释了为什么。我不完全知道如何解析这样的结构,但是您可能不必这样做。看来Erlang已经有一个名为public_key:pem_decode的函数为您执行此操作,该函数应该只接收整个openssl生成的密钥。根据{{​​3}},它还应该解析私钥。

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

答案 1 :(得分:0)

在Maarten的指导下,我设法弄清楚了(不知道我的OpenSSL私钥是“ X9.62”编码的;我认为它只是在base64中)。事实证明,您需要使用public_key模块而不是crypto模块。

这里是使用带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
相关问题