登录 phpseclib 并在 C# 中验证

Sign in phpseclib and Verify in C#

我正在尝试通过 PHP (phpseclib) 和 C# 验证消息的真实性。

不过C#端的验证好像有点问题

我尝试过的:

  1. 向 C# 提供 public 密钥,但让 C# 计算哈希和签名然后验证(输出:真)
  2. 将散列更改为 PHP 中计算的散列,但让 C# 计算签名然后验证(输出:真)
  3. 让 C# 使用 PHP 的计算哈希和签名然后验证(输出:False)

PHP代码:

//Load private key
$rsa = PublicKeyLoader::load("... private key ...", false);

//Set PKCS1 mode
$rsa->withPadding(RSA::ENCRYPTION_PKCS1 | RSA::SIGNATURE_PKCS1)->withHash("sha256");

//Generate and Convert the hash from 64 byte hex to 32 byte
$hash = pack("H*", hash("sha256", "test"));

//Sign the hash and encode it
$signed_hash = base64_encode($rsa->sign($hash));

//Encode the hash
$hash = base64_encode($hash);

C# 代码:

static void Main()
{
    //Create a new instance of RSA.
    using (RSA rsa = RSA.Create())
    {
        //Load public key from XML string
        rsa.FromXmlString("... public key ...");

        //Create an RSAPKCS1SignatureDeformatter object and pass it the RSA instance
        //to transfer the key information.
        RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa);
        RSADeformatter.SetHashAlgorithm("SHA256");

        //decode the hash
        var hash = Convert.FromBase64String("SHA256 Hash As Base64");
        var signedHash = Convert.FromBase64String("SHA256 Hash Signature As Base64");

        //Verify the hash and display the results to the console.
        if (RSADeformatter.VerifySignature(hash, signedHash))
        {
            Console.WriteLine("True");
        }
        else
        {
            Console.WriteLine("False");
        }
    }
}

两个代码都存在问题:

  • 默认情况下,phpseclib 使用 PSS 作为填充(此处和以下假定的 v3)。填充虽然明确设置为 PKCS#1 v1.5,但未使用,因为未应用 return 值。要使填充更改​​生效,必须考虑 return 值。
    顺便说一句,SHA256 是这里的默认值。 RSA::ENCRYPTION_PKCS1 在 signing/verifying 的上下文中被忽略,也可以被删除。

  • phpseclib 在签名时隐式散列数据。由于在当前的 phpseclib 代码中,哈希是另外显式生成的,因此完成了 double 哈希。这种双重散列不是必需的,可以删除。

  • 末尾的双重Base64编码也没有必要,也可以去掉

    总体:

    ...
    
    //Set PKCS1 mode
    $rsa = $rsa->withPadding(RSA::SIGNATURE_PKCS1)->withHash("sha256");
    
    //Sign the hash and encode it
    $signature = base64_encode($rsa->sign("test"));
    print($signature . PHP_EOL); 
    

    PKCS#1v1.5 是确定性的,即对于相同的输入数据,重复签名会产生相同的签名。


  • 与 PHP 代码不同,C# 代码中没有隐式散列,因此必须显式进行。

    然后可以使用 C# 代码进行验证:

    ...
    
    var hash = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("test"));
    var signature = Convert.FromBase64String("<Base64 encoded signature from PHP code>");
    Console.WriteLine(RSADeformatter.VerifySignature(hash, signature)); // True