.NET 4.8中C#实现JSON Webhook签名验证失败的排查与解决
JSON Webhook签名验证:.NET 4.8适配问题及解决办法
我需要验证JSON Webhook的签名,官方仅提供了JavaScript实现示例,该代码运行后控制台输出true:
const crypto = require("crypto"); const fs = require('fs'); const publicKey = fs.readFileSync('publicKey.pem', 'utf-8'); const payload = fs.readFileSync('payload.json', 'utf-8'); const signature = fs.readFileSync('signature.txt', 'utf-8'); function verify(publicKey, signature, payload) { const verifier = crypto.createVerify("RSA-SHA256"); verifier.update(payload); return verifier.verify( { key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }, Buffer.from(signature, 'base64') ); } const verified = verify(publicKey, signature, payload); console.log('Signature Verified: ', verified);
但我在.NET 4.8环境下编写C#对应逻辑时,验证结果始终返回false,最初的实现代码如下:
private static bool VerifySignature(string publicKeyPath, string payload, string signature) { byte[] byteToSign = Encoding.UTF8.GetBytes(payload); byte[] bsign = Convert.FromBase64String(signature); string pemText = File.ReadAllText(publicKeyPath); PemReader pr = new PemReader(new StringReader(pemText)); AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject(); RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey); RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider(); cryptoServiceProvider.ImportParameters(rsaParams); bool result = cryptoServiceProvider.VerifyData(byteToSign, bsign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); return result; }
问题原因
JS代码使用的是RSA-PKCS1-PSS填充模式,而上述C#代码采用的是普通PKCS#1 v1.5填充(RSASignaturePadding.Pkcs1),填充算法不匹配导致验证失败。
正确的.NET 4.8实现
通过使用BouncyCastle库的PssSigner类,实现与JS一致的PSS填充签名验证,以下代码可正常运行:
private static bool VerifySignature(string publicKeyPath, string payload, string signature) { byte[] byteToSign = Encoding.UTF8.GetBytes(payload); byte[] bsign = Convert.FromBase64String(signature); string pemText = File.ReadAllText(publicKeyPath); PemReader pr = new PemReader(new StringReader(pemText)); AsymmetricKeyParameter publicKey = (AsymmetricKeyParameter)pr.ReadObject(); PssSigner pssSigner = new PssSigner(new RsaEngine(), new Sha256Digest(), bsign.Length - 32 - 2); pssSigner.Init(false, publicKey); pssSigner.BlockUpdate(byteToSign, 0, byteToSign.Length); bool result = pssSigner.VerifySignature(bsign); return result; }
内容的提问来源于stack exchange,提问作者Yevgeny Granat
相关产品推荐
相关产品推荐

