我正在尝试跨 PHP (phpseclib) 和 C# 验证消息的真实性。
但是,C#端的验证似乎存在一些问题。
我尝试过的:
- 向 C# 提供公钥,但让 C# 计算哈希值和签名,然后进行验证(输出:True)
- 将哈希更改为在 PHP 中计算的哈希,但让 C# 计算签名然后验证(输出:True)
- 让 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,但由于未应用返回值,因此未使用它。为了使填充更改生效,必须考虑返回值。
顺便说一下,这里默认的是 SHA256。并且RSA::ENCRYPTION_PKCS1
在签名/验证上下文中会被忽略,也可以删除。phpseclib 在签名时隐式对数据进行哈希处理。由于在当前的 phpseclib 代码中,哈希值是另外显式生成的,因此完成了双重哈希值。这种双重哈希不是必需的,可以删除。
末尾的双重 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
关于c# - 登录 phpseclib 并在 C# 中验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70041715/