【问题标题】:ECDSA: Convert a binary public key of 60 bytes into PEM format for using it with PHP openssl_verify()ECDSA:将 60 字节的二进制公钥转换为 PEM 格式,以便与 PHP openssl_verify() 一起使用
【发布时间】:2019-10-22 07:35:00
【问题描述】:

我想用 PHP 证明一个 Wii 签名。我有 60 个字节的公钥作为二进制数据加上 4 个额外的字节。而且我知道它是 ECDSA(很可能是 B-233)。我已经用 C 实现了它,但是 PHP 解释器对我的实现来说太慢了。所以我调用外部C工具来确认签名。

但我想使用openssl_verify($data,$sig,$pubkey)。我的问题是第三个参数(公钥)。所以我必须将 ECDSA 信息和公钥转换为可接受的格式。

有什么想法吗?

进展

我尝试了更多,并使用不同的算法创建了密钥(例如 sect233k1、sect233r1)。我的计划是用我的密钥注入一个如此生成的公钥。现在我收到错误消息:

error:0906D06C:PEM routines:PEM_read_bio:no start line

公钥如下所示:

-----BEGIN PUBLIC KEY-----
MFIwEAYHKoZIzj0CAQYFK4EEABoDPgAEAS+URvH1x1GXfTw6VZh8tLVPq3bgYwl8
g8OHtCKuADoZ8YayIHkJuYEqTJZBgI8YMX8FtrI8BOlBiBLF
-----END PUBLIC KEY-----

【问题讨论】:

  • 你怎么知道这 4 个字节不是公钥的一部分?密钥属于哪条曲线?
  • 我知道,因为 C 实现忽略了 4 个字节。曲线很可能是 B-233。但我目前的主要问题是让任何 $pubkey 运行。即使使用openssl ec ... 创建的 PEM 文件,openssl_verify() 也会抛出 supplied key param cannot be coerced into a public key
  • 但我目前的主要问题是让 any $pubkey 运行。 这是否意味着您正在使用 OpenSSL 创建密钥对B-233 签名文件验证失败?我无法重现!上面描述的场景对我有用。发布您的 OpenSSL 声明。
  • 关键参数的问题是,安装的 openssl 删除了 NIST 支持,因此 php 不知道算法。更换服务器后,这个问题就消失了。无论如何,将签名转换为 pub 密钥并对其进行验证会导致错误 error:0906D06C:PEM routines:PEM_read_bio:no start line

标签: php ecdsa


【解决方案1】:

是的,你在正确的轨道上。假设曲线已知,可以如下推导出公钥(本质上是基于这个answer的一个想法):

  • 在下文中,假定曲线NIST B-233 (aka sect233r1) 的原始公钥大小为 60 字节。如果曲线不同,则必须相应交换曲线ID,并改用曲线公钥的大小。

  • 使用与您的曲线匹配的 DER 格式的 任何 公钥。

    如果您没有,请使用 OpenSSL 创建与您的曲线匹配的 PEM 格式的私钥。私钥具有 SEC1 格式:

      openssl ecparam -out <path to private key file> -genkey -name sect233r1 -noout
    

    从此私钥导出公钥作为 DER。公钥具有 X.509 格式:

      openssl ec -in <path to private key file> -pubout -outform der -out <path to public key file>
    
  • 使用十六进制编辑器确定公钥的二进制数据,例如online。在这一点上,利用了原始公钥直接位于公钥末尾这一事实。对于 B-233,原始公钥的长度为 60 个字节,即生成的公钥的最后 60 个字节必须与当前原始公钥的 60 个字节交换。这是作为 DER 搜索的公钥,其中包含您的原始公钥。

  • 对于使用 OpenSSL 的验证过程,如果使用 -keyform DER 选项,则 DER 格式就足够了,例如

      openssl dgst -ecdsa-with-SHA1 -keyform DER -verify <path to public key file> -signature <path to signature file> <path to file for which signature is>
    
  • 对于openssl_verify 的 PHP 验证过程,PEM 格式是必需的。如果 DER 数据是 Base64 编码的,则转换为 PEM 格式是最简单的,例如online。最后,您必须添加页眉 (-----BEGIN PUBLIC KEY-----\n) 和页脚 (\n-----END PUBLIC KEY-----)。请确保在页眉之后和页脚之前正好有一个换行符。在最后一个参数中,必须指定用于创建签名的哈希算法,例如:

      $data = hex2bin(<binary data from file for which signature is>); 
      $signature = hex2bin(<binary data from signature file>);
      $pub_key_id = "-----BEGIN PUBLIC KEY-----\nMFIwEAYHKoZIzj0CAQYFK4EEABsDPgAEAfERAiIKyPaby4+efUcRmv8ucekCFMnjc6fN1IeQAO6EMcKCcFLhKRJUHijUNp0Dv/CWYLUdeN0qNOI6\n-----END PUBLIC KEY-----";
      $result = openssl_verify($data, $signature, $pub_key_id, OPENSSL_ALGO_SHA1);
      print($result);
    

【讨论】:

  • 第一个观点:这正是我所做的。稍后我会逐步尝试,以找出我的任何错误。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
  • 1970-01-01
相关资源
最近更新 更多