2016-08-14 23 views
2

在Elixir中构建一个pem文件需要几个步骤,包括构建一个实体。在OTP 17,以下工作:升级到OTP 18会中断public_key库的使用

{public, private} = :crypto.generate_key(:ecdh, :secp256k1) 
ec_entity = {:ECPrivateKey,                                                
    1,                                                   
    :binary.bin_to_list(private),                                            
    {:namedCurve, {1, 3, 132, 0, 10}},                                           
    {0, public}} 
der_encoded = :public_key.der_encode(:ECPrivateKey, ec_entity) 
pem = public_key.pem_encode([{:ECPrivateKey, der_encoded, :not_encrypted}]) 

但使用OTP 18,出现以下错误:

{public, private} = :crypto.generate_key(:ecdh, :secp256k1) 
ec_entity = {:ECPrivateKey,                                                
    1,                                                   
    :binary.bin_to_list(private),                                            
    {:namedCurve, {1, 3, 132, 0, 10}},                                           
    {0, public}} 
der_encoded = :public_key.der_encode(:ECPrivateKey, ec_entity) 
** (MatchError) no match of right hand side value: {:error, {:asn1, :badarg}} 
public_key.erl:253: :public_key.der_encode/2 

这是什么错误的根源?

回答

2

错误的来源是在OTP 17和OTP 18之间构建public_key实体的方式发生了变化。如果我们从pem文件开始反转进程,我们可以看到差异。

OTP 17:

iex(6)> pem = "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIJniJF4vtTqE4wS5AkhmMZsHIbil0l3XfRButkw5IJYFoAcGBSuBBAAK\noUQDQgAEtxm+jijBB0JxZTceHnCHE0HpMXJp1ScVUZ5McvDUVsS/Dek8IdAsMOPz\nnnVALflZzXtH/wU9p2LrFdJeuXwL8g==\n-----END EC PRIVATE KEY-----\n\n" 
"-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIJniJF4vtTqE4wS5AkhmMZsHIbil0l3XfRButkw5IJYFoAcGBSuBBAAK\noUQDQgAEtxm+jijBB0JxZTceHnCHE0HpMXJp1ScVUZ5McvDUVsS/Dek8IdAsMOPz\nnnVALflZzXtH/wU9p2LrFdJeuXwL8g==\n-----END EC PRIVATE KEY-----\n\n" 
iex(7)> [{type, decoded, _}] = :public_key.pem_decode(pem) 
[{:ECPrivateKey, 
    <<48, 116, 2, 1, 1, 4, 32, 153, 226, 36, 94, 47, 181, 58, 132, 227, 4, 185, 2, 72, 102, 49, 155, 7, 33, 184, 165, 210, 93, 215, 125, 16, 110, 182, 76, 57, 32, 150, 5, 160, 7, 6, 5, 43, 129, 4, 0, 10, ...>>, 
    :not_encrypted}] 
iex(8)> :public_key.der_decode(type, decoded) 
{:ECPrivateKey, 1, 
[153, 226, 36, 94, 47, 181, 58, 132, 227, 4, 185, 2, 72, 102, 49, 155, 7, 33, 
    184, 165, 210, 93, 215, 125, 16, 110, 182, 76, 57, 32, 150, 5], 
{:namedCurve, {1, 3, 132, 0, 10}}, 
{0, 
    <<4, 183, 25, 190, 142, 40, 193, 7, 66, 113, 101, 55, 30, 30, 112, 135, 19, 65, 233, 49, 114, 105, 213, 39, 21, 81, 158, 76, 114, 240, 212, 86, 196, 191, 13, 233, 60, 33, 208, 44, 48, 227, 243, 158, 117, ...>>}} 

OTP 18:

iex(5)> [{type, decoded, _}] = :public_key.pem_decode(pem) 
[{:ECPrivateKey, 
    <<48, 116, 2, 1, 1, 4, 32, 153, 226, 36, 94, 47, 181, 58, 132, 227, 4, 185, 2, 72, 102, 49, 155, 7, 33, 184, 165, 210, 93, 215, 125, 16, 110, 182, 76, 57, 32, 150, 5, 160, 7, 6, 5, 43, 129, 4, 0, 10, ...>>, 
    :not_encrypted}] 
iex(6)> entity = :public_key.der_decode(type, decoded) 
{:ECPrivateKey, 1, 
<<153, 226, 36, 94, 47, 181, 58, 132, 227, 4, 185, 2, 72, 102, 49, 155, 7, 33, 184, 165, 210, 93, 215, 125, 16, 110, 182, 76, 57, 32, 150, 5>>, 
{:namedCurve, {1, 3, 132, 0, 10}}, 
<<4, 183, 25, 190, 142, 40, 193, 7, 66, 113, 101, 55, 30, 30, 112, 135, 19, 65, 233, 49, 114, 105, 213, 39, 21, 81, 158, 76, 114, 240, 212, 86, 196, 191, 13, 233, 60, 33, 208, 44, 48, 227, 243, 158, 117, 64, ...>>} 

所不同的是在公共和私有密钥如何表示。

一个ECPrivateKey记录的签名是: ECPrivateKey'{ version, privateKey, parameters, publicKey}

在Erlang中18,这两个值在普通二进制表示的,在图17中,专用密钥是一个列表,并且该公开密钥是一个元组的一部分,{0, binary}

因此,为了正确构建pem文件,必须更改实体表示。

{public, private} = :crypto.generate_key(:ecdh, :secp256k1) 
entity = {:ECPrivateKey,                                                
    1,                                                   
    private,                                                 
    {:namedCurve, {1, 3, 132, 0, 10}},                                           
    public}  

使用记录的新表示法可以解决问题。

0

我没有真正检查为什么你的版本在某些版本上有效,但是我有一些适用于所有这些erlang版本的代码:19.0,18.2.1,18.1,18.0,17.5,R16B03(在travis上运行)。

-include_lib("public_key/include/public_key.hrl"). 

genPEMKey() -> 
    CurveId = secp256k1, 
    {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId), 
    Key = #'ECPrivateKey'{version = 1, 
         privateKey = PrivKey, 
         parameters = { 
         namedCurve, 
         pubkey_cert_records:namedCurves(CurveId)}, 
         publicKey = PubKey}, 
    DERKey = public_key:der_encode('ECPrivateKey', Key), 
    public_key:pem_encode([{'ECPrivateKey', DERKey, not_encrypted}]). 

这段代码是基于OTP代码库中发现的例子:

https://github.com/erlang/otp/blob/master/lib/public_key/test/erl_make_certs.erl#L407

+0

我只是说这个答案有一个工作的例子包裹起来。我认为@ philosodad的答案解释了为什么它打破了,以及如何正确地解决它。 – clarete