I need to verify signature of a JSON webhook. In the documentation there is only JavaScript example of how to do this:
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);
The above code prints "true" in the console log. I'm trying to simulate the same in C# and it always returns 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;
}
I tried different approaches in C#, the above one looks cleaner and shorter than the other ones. What am I doing wrong? Please note that I use .NET 4.8, so I don't have methods like RSACryptoServiceProvider.ImportFromPem
that are available only from version 5. Thanks
UPDATE - This code works properly:
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;
}
This code works properly:
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;
}