使用 Web Crypto API 生成的 PHP ECDSA 签名进行验证

问题描述 投票:0回答:1

我有以下任务。 我必须生成 ECDSA 密钥对。使用私钥对数据进行签名并在 PHP 中验证签名。由于某些未知的原因,我无法成功验证数据。

这是我的 javascript 示例,它生成密钥并签署数据。

(async () => {

  async function arrayBufferToBase64(arrayBuffer) {
    var binary = '';
    var bytes = new Uint8Array(arrayBuffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
  }

  let keyPair = await window.crypto.subtle.generateKey(
    {
      name: "ECDSA",
      namedCurve: "P-256",
    },
    false,
    ["sign", "verify"]);

    let data = 'text_value';

    let signature = await window.crypto.subtle.sign({
      name: "ECDSA",
      hash: { name: "SHA-256" },
    }, keyPair.privateKey, new TextEncoder().encode(data));
    
    console.log('Data: ' + data);

    console.log('Signature: ' + await arrayBufferToBase64(signature));

    console.log('Public key: ' + await arrayBufferToBase64(await window.crypto.subtle.exportKey('spki', keyPair.publicKey)));

})();

此代码给出类似的输出。

Data: text_value
Signature: TfsoDx8TyuAth7SzsoagHVykRU+eNWaGOWEulrSjZ57KKa2T/8zO/7+/8TvRXLvuXSbEloRFbigzUpIlOlGMcw==
Public key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE01iwlSEr1pLOLu2Ks9gxMhH7C3NWQ95yKO2vvv7XYfRGKAVRaLVLJ6j3J6klnNez5kWeECdJ1OhoQULEyokEZQ==

有了数据、签名和公钥,我将它们发送到 PHP 来验证签名。

我有以下 PHP 代码(我使用 php 8.1):

<?php

$data = 'text_value';
$signature = base64_decode("TfsoDx8TyuAth7SzsoagHVykRU+eNWaGOWEulrSjZ57KKa2T/8zO/7+/8TvRXLvuXSbEloRFbigzUpIlOlGMcw==");
$public_key = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE01iwlSEr1pLOLu2Ks9gxMhH7C3NWQ95yKO2vvv7XYfRGKAVRaLVLJ6j3J6klnNez5kWeECdJ1OhoQULEyokEZQ==";
$public_key = "-----BEGIN PUBLIC KEY-----\n$public_key\n-----END PUBLIC KEY-----";

echo "Data: $data\n\n";
echo "Public key: \n$public_key\n\n";

$verify = openssl_verify($data, $signature, $public_key, OPENSSL_ALGO_SHA256);
echo $verify === 1 ? 'Valid signature' : 'Invalid signature';

echo "\n\nopenssl_error_string(): " . openssl_error_string() . "\n\n";

我做错了什么?

javascript php cryptography ecdsa webcrypto-api
1个回答
0
投票

ECDSA 使用不同的签名格式:ASN.1/DER 和 IEEE P1363 格式。 WebCrypto采用IEEE P1363,PHP/OpenSSL采用ASN.1/DER格式。为了验证成功,必须将IEEE P1363格式的签名转换为ASN.1/DER格式。

示例中的 IEEE1363 签名是十六进制编码的(而不是 Base64 编码的):

4dfb280f1f13cae02d87b4b3b286a01d5ca4454f9e35668639612e96b4a3679eca29ad93ffccceffbfbff13bd15cbbee5d26c49684456e28335292253a518c73

转换为 ASN.1/DER 格式后:

304502204dfb280f1f13cae02d87b4b3b286a01d5ca4454f9e35668639612e96b4a3679e022100ca29ad93ffccceffbfbff13bd15cbbee5d26c49684456e28335292253a518c73

如果使用这种格式的签名,则PHP代码验证成功。

在这里您会找到两种格式的说明,其中也解释了上述转换。

© www.soinside.com 2019 - 2024. All rights reserved.