php - 如何在 php 中以十六进制格式签署 ECDSA 签名并编码为 DER 格式?
问题描述
如何Keccak256
使用密钥对 Tx 数据进行签名,包括 ETH 哈希地址签名secp256k1 (ECDSA)
并编码为DER
十六进制格式并在 php 中验证?
我只想使用附带的 php 库、openssl 和其他库来制作secp256k1
私钥和公钥、签名并转换为DER
格式hex
以制作我的 cryptcoin 样本。
以太坊地址是由secp256k1 EDSA
密钥生成的,256 bits/64 character
用(sha-3-256)哈希算法对由私钥生成的公钥进行Keccak256
哈希计算以计算哈希,然后从哈希字符串中取出十六进制的最后40个字符,添加校验和,并将x0
前缀添加到哈希字符串。
该示例在github.com/simplito/elliptic-php
repo 中toDER()
显示为elliptic-php/lib/EC/Signature.php
. 该库正在使用BN-php
,但我只想使用 php 库openssl
和其他库。
// https://github.com/simplito/elliptic-php ECDSA sample
<?php
use Elliptic\EC;
// Create and initialize EC context
// (better do it once and reuse it)
$ec = new EC('secp256k1');
// Generate keys
$key = $ec->genKeyPair();
// Sign message (can be hex sequence or array)
$msg = 'ab4c3451';
$signature = $key->sign($msg);
// Export DER encoded signature to hex string
$derSign = $signature->toDER('hex');
openssl_pkey_new()
和openssl_sign()
函数可以制作新的secp256k1
私钥和公钥并签名,但不能将公钥转换为DER
格式hex
以通过哈希keccak256
算法制作地址。
签署 Tx 哈希需要 JSON 字符串 Tx 数据中的往返 ETH 地址,{address:{to:address1,from:address2},amount:0,timestamp:timestamp tx, hash:sha256hash, previousHash:hash, difficulty:2...}
并且openssl_pkey_new() openssl_pkey_export()
需要制作私钥和公钥来制作 ETH 地址。
因为,openssl_pkey_new() openssl_pkey_export()
对于OPENSSL_KEYTYPE_EC
返回DER bin
键,我需要将它们转换为十六进制。
我已经尝试过openssl_pkey_new()
功能openssl_sign()
,但我无法使用简单的功能转换为DER
格式。hex
openssl_pkey_new()
生成新secp256k1
密钥对的函数,如生成 256 位 ECDSA 私钥问题中所示。
$config = [
"config" => getenv('OPENSSL_CONF'),
'private_key_type' => OPENSSL_KEYTYPE_EC,
'curve_name' => 'secp256k1'
];
$res = openssl_pkey_new($config);
if (!$res) {
echo 'ERROR: Fail to generate private key. -> ' . openssl_error_string();
exit;
}
// Generate Private Key
openssl_pkey_export($res, $priv_key, NULL, $config);
// Get The Public Key
$key_detail = openssl_pkey_get_details($res);
$pub_key = $key_detail["key"];
echo "priv_key:<br>".$priv_key;
echo "<br><br>pub_key:<br>".$pub_key;
并用钥匙签名。
openssl_sign($hashdata, $signature, $private_key);
有什么方法可以使用 php 库将密钥转换为DER
十六进制?
解决方案
好的,现在我知道你想要什么我已经调查过了,不幸的是我认为你不走运。首先要澄清的是,对于以太坊,您需要 DER 中的签名,并且密钥格式可能因您的软件而异,但对于以太坊帐户地址,您不需要 DER 中的密钥。具体来说,地址是通过以下方式计算的:
将公钥点表示为原始 X、Y 坐标,没有像 DER 这样的元数据,甚至没有像 X9.62 这样的单个字节,也没有像 base64 或 hex 这样的编码
取 Keccak256 哈希并取最后 20 个字节,可以用 0x 前缀的十六进制表示(例如显示)总共 42 个字符
对于第 1 步,OpenSSL 以及 php 的内置模块使用的密钥是 PEM 格式,正如您在示例中看到的那样,它由以 base64 编码的 ASN.1(DER 或有时是 BER)主体组成,带有换行符和 header/拖车线。具体来说,公钥采用RFC7468 第 13 节定义的格式,其内容是 X.509 和 PKIX 定义的 SubjectPublicKeyInfo 结构,即RFC5280 4.1.2.7,其特定算法的内容在其他标准中定义;这里的案例,X9 风格的 EC,在RFC3279 2.3.5中定义并由RFC5480 2.2简化参考 X9.62 和 SEC1。(哇!)虽然这些标准允许多种选择,但 PHP 中的 OpenSSL 始终使用 X9.62 未压缩点格式和 DER 编码,因此对于这条曲线,您需要的以太坊数据只是从 PEM 解码的 DER 的最后 64 个字节:
$der=base64_decode(str_replace(array("-----BEGIN PUBLIC KEY-----\n","-----END PUBLIC KEY-----\n"),"",$pub_key));
$raw=substr($der,-64);
但是第2步是一个问题。尽管在 FIPS202 中标准化的 SHA3 和 SHAKE 是 Keccak 的实例,但以太坊使用的哈希是 Keccak 的不同且非标准的实例,OpenSSL 没有实现它,因此 php 本身也没有(不添加库)。
推荐阅读
- c# - 如何在创建工具的同时创建工具事件?(C#,Windows 窗体)
- sql - 如何按特定列限制?
- javascript - 从页面上的表单输出数据反应
- css - `html` 和 `html, body` 选择器在渲染结果方面有什么区别吗
- laravel - 删除功能不适用于控制器
- c# - 将 MagickImage 转换为位图
- flutter - 颤动中浮动操作按钮上的通知徽章
- javascript - 如何使用javascript根据数组项过滤对象?
- google-tag-manager - 谁知道 Facebook 标准转换的 GTM 脚本:预约预约和电话号码点击?
- r - 使用 facet_wrap_paginate 循环无序交替生成的图