RSA 签名验证适用于 .Net 核心但不适用于 .Net 4.8
RSA Signature verification works on .Net core but not on .Net 4.8
我有一个非常简单的 .Net 控制台应用程序,我将在此处粘贴它,它执行 RSA 签名验证并且在 .Net Core 3.1 上完美运行。但是 .net 4.8 控制台应用程序上完全相同的代码(复制粘贴没有更改)表示签名无效。
我不知道发生了什么。这个签名在我测试过的所有其他语言甚至在线 RSA 签名验证器中都是可以的。
两者都使用 Nuget BouncyCastle 1.8.6.1。
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
static void Main()
{
byte[] publicKeyData = Convert.FromBase64String("LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUE1RGxFVVRtQUF0ZGIvVXZGYnpiWQpxbVJYNGZ6VW80WGhIbTk1VDRvbS9OaVplbFBNYzFOUjNNMVV0OFIyQkdRdmt2MndEUUkzblk2ZklLeUtWM3VVCjR4ZTIvMW1IQkdaSVB5WHRLKzdaelJJbkl1aTVtT0x2R2FTOVBlaFJSMTVvTTZXT3pweTdOay9QRjlUUHltWEEKWEZnQWZTZFo3bUx4QldqUktjMGorUTNZRGZuWi9OMzUzZUJEc1FWN2tkamVFYVpmK3RUZll5eFVpY2RTUjZVUgpsOUl4YW5yc2RqVjF1TndmWm5yYTdDVTFhcElCcjNFeDZBb20yWDVtNjZ4TjRXeVJHRCtOS3ZBeitNVHZkSU4vClNLVU1UMnA0aEpWc3FiZ2hGN2FZeDYxNGxHbmN5dTZQNDQ4QjlBcjh2R0NLbDRnMGl0eUtjbGJSZS9wMjh2U2oKWkxwYkVjZkY2eHlJYlJraWZEbHJITUlQS1JkazRIV25wamQvaEdHN2lZN1VWYWJuUmxpVUExVDQ3T2kyaENVNwoxKzVkT1F4dDdRNVFxUFNURFNZc1E4M1c5VStmZ0xMYVVWSFA5SzhpdG1qWW1ueFF2a1FqUnc5YUhYTk5Db2M4ClZrdFBnY1A0UFJTZ0dLL2JWbWtIbjBrWDMvclVEZG9zV1dHaURUWnZwRFRKUHo3UVpmbENFRDFzV0xIaEMxOU8KdWtFdEFQYVR5VkJ5RC9yUURoTWJyb2RIVmRJNjhZeE5UdnNpU2NxdlMvZlBmYUVUcUJsVzJpQXVndE5TZGIzSApEOFVFUUgzTUE0K044RXVtK1o5bzQ2Vnk2c0hOVytVVE0wRDVwOXBvWWEwV1dxQ0hLc2ZqbFcyN0dIaDF1WDZKCmNHd0NBc1pBT2N6MEpPRWVuSDFtYXhrQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=");
string decodedPublicKeyString = Encoding.UTF8.GetString(publicKeyData);
string signedData = "RHClqUohXp5QOvBAYqTMa63PuYXahqKEDUIdCYfA/qq1mT18QSVIu5gneYbYjAQH4dWE5wytMnIihNZkFcY06WjIeTwJJVHZPmp/SGQvO44ouF2Qhb6n9HmgdqLzL1gPUVeElyeytDvcaRgkI2tqIZ+3a1QERVpH49xGQzf2N1YcFycOrm08CHO3o9jTWJrtURntgOV9cGUStZy2mEJ5CvNo8+5Fniidsjpn4Bem/34PdFNRjVRgrVVqVjaB6ICB6KTMPzd/jPF02cPGA5n7j5Stn9DpU1uyicEhCsMK/zxrfSYpKdXH74fjIP7Rw9HlWnAVlLv/pkVpCcRLLn7iW1V6MPvzuL9Rft2QK61RDSo4Ntka6a48+FJPB2v9pTY8qu4jIUcpLGX+wYnHCt9nZnZ4UlFh6BKDFrpH1tZJ2XreS2qGlSiBii0j30VyjCinEz8rIFFes7kGbWm/6jdXZliWbgPpZ7shEVSTwPDy6UVeD0LP9m/OxLNfCF31bOLkacxA8qv5PvbntWUcuNsUqdrk5YKcaDdQq4texWm1CQtBs7gYVwARYHusHi6ISUCHGN0RnULcPLa7jfZVq/y56DV0tuxhxsxyu9BpCx6Rm5AlYJJcgRyRRsaldivHBdvNJZCDPIVBBmpbpfKoctwWSvROmnirCFc9iQb8gnNNtlc=";
var signedBytes = Convert.FromBase64String(signedData);
VerifyWithPublicKey("12345789", signedBytes, decodedPublicKeyString);
}
private static bool VerifyWithPublicKey(string data, byte[] signedHash, string decodedPublicKey)
{
try
{
using (RSA rsa = RSA.Create())
{
byte[] hash;
using (SHA256 shaM = SHA256.Create())
{
hash = shaM.ComputeHash(Encoding.ASCII.GetBytes(data));
}
using (var keyreader = new StringReader(decodedPublicKey))
{
var pemReader = new PemReader(keyreader);
var y = (RsaKeyParameters)pemReader.ReadObject();
var rsaParameters = new RSAParameters();
rsaParameters.Modulus = y.Modulus.ToByteArray();
rsaParameters.Exponent = y.Exponent.ToByteArray();
rsa.ImportParameters(rsaParameters);
RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa);
RSADeformatter.SetHashAlgorithm("SHA256");
if (RSADeformatter.VerifySignature(hash, signedHash))
{
Console.WriteLine("The signature was verified.");
return true;
}
else
{
Console.WriteLine("The signature was not verified.");
return false;
}
}
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
return false;
}
}
运行 在我的机器上对 4.6.2 和 4.7.2 产生 false
。然而,改变
rsaParameters.Modulus = y.Modulus.ToByteArray();
rsaParameters.Exponent = y.Exponent.ToByteArray();
至
rsaParameters.Modulus = y.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = y.Exponent.ToByteArrayUnsigned();
似乎解决了这个问题。我希望这对你有用。
我有一个非常简单的 .Net 控制台应用程序,我将在此处粘贴它,它执行 RSA 签名验证并且在 .Net Core 3.1 上完美运行。但是 .net 4.8 控制台应用程序上完全相同的代码(复制粘贴没有更改)表示签名无效。
我不知道发生了什么。这个签名在我测试过的所有其他语言甚至在线 RSA 签名验证器中都是可以的。
两者都使用 Nuget BouncyCastle 1.8.6.1。
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
static void Main()
{
byte[] publicKeyData = Convert.FromBase64String("LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUE1RGxFVVRtQUF0ZGIvVXZGYnpiWQpxbVJYNGZ6VW80WGhIbTk1VDRvbS9OaVplbFBNYzFOUjNNMVV0OFIyQkdRdmt2MndEUUkzblk2ZklLeUtWM3VVCjR4ZTIvMW1IQkdaSVB5WHRLKzdaelJJbkl1aTVtT0x2R2FTOVBlaFJSMTVvTTZXT3pweTdOay9QRjlUUHltWEEKWEZnQWZTZFo3bUx4QldqUktjMGorUTNZRGZuWi9OMzUzZUJEc1FWN2tkamVFYVpmK3RUZll5eFVpY2RTUjZVUgpsOUl4YW5yc2RqVjF1TndmWm5yYTdDVTFhcElCcjNFeDZBb20yWDVtNjZ4TjRXeVJHRCtOS3ZBeitNVHZkSU4vClNLVU1UMnA0aEpWc3FiZ2hGN2FZeDYxNGxHbmN5dTZQNDQ4QjlBcjh2R0NLbDRnMGl0eUtjbGJSZS9wMjh2U2oKWkxwYkVjZkY2eHlJYlJraWZEbHJITUlQS1JkazRIV25wamQvaEdHN2lZN1VWYWJuUmxpVUExVDQ3T2kyaENVNwoxKzVkT1F4dDdRNVFxUFNURFNZc1E4M1c5VStmZ0xMYVVWSFA5SzhpdG1qWW1ueFF2a1FqUnc5YUhYTk5Db2M4ClZrdFBnY1A0UFJTZ0dLL2JWbWtIbjBrWDMvclVEZG9zV1dHaURUWnZwRFRKUHo3UVpmbENFRDFzV0xIaEMxOU8KdWtFdEFQYVR5VkJ5RC9yUURoTWJyb2RIVmRJNjhZeE5UdnNpU2NxdlMvZlBmYUVUcUJsVzJpQXVndE5TZGIzSApEOFVFUUgzTUE0K044RXVtK1o5bzQ2Vnk2c0hOVytVVE0wRDVwOXBvWWEwV1dxQ0hLc2ZqbFcyN0dIaDF1WDZKCmNHd0NBc1pBT2N6MEpPRWVuSDFtYXhrQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=");
string decodedPublicKeyString = Encoding.UTF8.GetString(publicKeyData);
string signedData = "RHClqUohXp5QOvBAYqTMa63PuYXahqKEDUIdCYfA/qq1mT18QSVIu5gneYbYjAQH4dWE5wytMnIihNZkFcY06WjIeTwJJVHZPmp/SGQvO44ouF2Qhb6n9HmgdqLzL1gPUVeElyeytDvcaRgkI2tqIZ+3a1QERVpH49xGQzf2N1YcFycOrm08CHO3o9jTWJrtURntgOV9cGUStZy2mEJ5CvNo8+5Fniidsjpn4Bem/34PdFNRjVRgrVVqVjaB6ICB6KTMPzd/jPF02cPGA5n7j5Stn9DpU1uyicEhCsMK/zxrfSYpKdXH74fjIP7Rw9HlWnAVlLv/pkVpCcRLLn7iW1V6MPvzuL9Rft2QK61RDSo4Ntka6a48+FJPB2v9pTY8qu4jIUcpLGX+wYnHCt9nZnZ4UlFh6BKDFrpH1tZJ2XreS2qGlSiBii0j30VyjCinEz8rIFFes7kGbWm/6jdXZliWbgPpZ7shEVSTwPDy6UVeD0LP9m/OxLNfCF31bOLkacxA8qv5PvbntWUcuNsUqdrk5YKcaDdQq4texWm1CQtBs7gYVwARYHusHi6ISUCHGN0RnULcPLa7jfZVq/y56DV0tuxhxsxyu9BpCx6Rm5AlYJJcgRyRRsaldivHBdvNJZCDPIVBBmpbpfKoctwWSvROmnirCFc9iQb8gnNNtlc=";
var signedBytes = Convert.FromBase64String(signedData);
VerifyWithPublicKey("12345789", signedBytes, decodedPublicKeyString);
}
private static bool VerifyWithPublicKey(string data, byte[] signedHash, string decodedPublicKey)
{
try
{
using (RSA rsa = RSA.Create())
{
byte[] hash;
using (SHA256 shaM = SHA256.Create())
{
hash = shaM.ComputeHash(Encoding.ASCII.GetBytes(data));
}
using (var keyreader = new StringReader(decodedPublicKey))
{
var pemReader = new PemReader(keyreader);
var y = (RsaKeyParameters)pemReader.ReadObject();
var rsaParameters = new RSAParameters();
rsaParameters.Modulus = y.Modulus.ToByteArray();
rsaParameters.Exponent = y.Exponent.ToByteArray();
rsa.ImportParameters(rsaParameters);
RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa);
RSADeformatter.SetHashAlgorithm("SHA256");
if (RSADeformatter.VerifySignature(hash, signedHash))
{
Console.WriteLine("The signature was verified.");
return true;
}
else
{
Console.WriteLine("The signature was not verified.");
return false;
}
}
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
return false;
}
}
运行 在我的机器上对 4.6.2 和 4.7.2 产生 false
。然而,改变
rsaParameters.Modulus = y.Modulus.ToByteArray();
rsaParameters.Exponent = y.Exponent.ToByteArray();
至
rsaParameters.Modulus = y.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = y.Exponent.ToByteArrayUnsigned();
似乎解决了这个问题。我希望这对你有用。