升级到OTP 18打破了public_key库的使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了升级到OTP 18打破了public_key库的使用相关的知识,希望对你有一定的参考价值。

在Elixir中构建pem文件需要几个步骤,包括构建实体。在OTP 17中,以下工作:

{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

这个错误的来源是什么?

答案

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

OTP 17:

iex(6)> pem = "-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIJniJF4vtTqE4wS5AkhmMZsHIbil0l3XfRButkw5IJYFoAcGBSuBBAAK
oUQDQgAEtxm+jijBB0JxZTceHnCHE0HpMXJp1ScVUZ5McvDUVsS/Dek8IdAsMOPz
nnVALflZzXtH/wU9p2LrFdJeuXwL8g==
-----END EC PRIVATE KEY-----

"
"-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIJniJF4vtTqE4wS5AkhmMZsHIbil0l3XfRButkw5IJYFoAcGBSuBBAAK
oUQDQgAEtxm+jijBB0JxZTceHnCHE0HpMXJp1ScVUZ5McvDUVsS/Dek8IdAsMOPz
nnVALflZzXtH/wU9p2LrFdJeuXwL8g==
-----END EC PRIVATE KEY-----

"
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}      

使用记录的新表示将解决问题。

另一答案

我没有真正检查为什么你的版本适用于某些版本,但我有一些代码适用于所有这些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

以上是关于升级到OTP 18打破了public_key库的使用的主要内容,如果未能解决你的问题,请参考以下文章

Jenkins workflowLibs库的使(妙)用

如何安装特定版本的 Erlang/OTP?

jquery 3.0.0 升级打破了 html 表格功能

Erlang/OTP 18.0 正式版发布

升级到 Webpack 5 打破 Storybook 5

C#MVC5升级打破了Javascript加载