I have some legacy .NET Framework code for signing and checking signatures which I need to port to .NET Core.
This is the existing .NET Framework code:
public static bool CheckSignature_NetFramework(string payload, string signature, string publicKey)
{
try
{
using (var rsa = RSA.Create())
using (var shaHash = SHA256.Create())
{
rsa.FromXmlString(publicKey);
var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA256");
return rsaDeformatter.VerifySignature(hash, Convert.FromBase64String(signature));
}
}
catch
{
return false;
}
}
public static string CreateSignature_NetFramework(string payload, string privateKey)
{
using (var rsa = RSA.Create())
using (var shaHash = SHA256.Create())
{
rsa.FromXmlString(privateKey);
var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
rsaFormatter.SetHashAlgorithm("SHA256");
return Convert.ToBase64String(rsaFormatter.CreateSignature(hash));
}
}
And this is what I came up with for the equivalent .NET Core implementation:
public static bool CheckSignature_NetCore(string payload, string signature, string publicKey)
{
try
{
using (var rsa = RSA.Create())
using (var shaHash = SHA256.Create())
{
rsa.FromXmlString(publicKey);
var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
return rsa.VerifyData(hash, Convert.FromBase64String(signature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
}
catch
{
return false;
}
}
public static string CreateSignature_NetCore(string payload, string privateKey)
{
using (var rsa = RSA.Create())
using (var shaHash = SHA256.Create())
{
rsa.FromXmlString(privateKey);
var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
return Convert.ToBase64String(rsa.SignData(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
}
public static void FromXmlString(this RSA rsa, string xmlString)
{
RSAParameters parameters = new RSAParameters();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
{
foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
{
switch (node.Name)
{
case "Modulus": parameters.Modulus = Convert.FromBase64String(node.InnerText); break;
case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
}
}
}
else
{
throw new Exception("Invalid XML RSA key.");
}
rsa.ImportParameters(parameters);
}
I can successfully verify a signature which was created using the same environment. But verifying a signature created with CreateSignature_NetFramework
using CheckSignature_NetCore
fails.
So it looks like my .NET Core implementation is not the exact equivalent to the .NET Framework implementation.
How can I verify a signature created using CreateSignature_NetFramework
in .NET Core?