0

I have an application that needs to sign certain data and then confirm that the signature is valid. The algorithm to use is RSA SHA 256. I have a certificate with its respective private key in the Windows certificate store. I have searched in several articles and on this I have based. I have no problem creating the signature. My problem is that when trying to confirm if the signature is valid with the public key, the VerifyData method returns False. I don't have a lot of experience working with C # and encryption and I can't see what's wrong with this code. Unfortunately I am working with an old framework (4.5)

X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);

var certificates = store.Certificates.Find(X509FindType.FindBySerialNumber, "XXXXXXXXXXXXXX", false);
var certificate = certificates(0);

store.Close();

var privKey = (RSACryptoServiceProvider)certificate.PrivateKey;

var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
var cspparams = new CspParameters(enhCsp.ProviderType, enhCsp.ProviderName, privKey.CspKeyContainerInfo.KeyContainerName);
privKey = new RSACryptoServiceProvider(cspparams);

byte[] sig = privKey.SignData(dataToSign, CryptoConfig.MapNameToOID("SHA256"));

bool isValid = privKey.VerifyData(dataToSign, CryptoConfig.MapNameToOID("SHA256"), sig);
string Signbase64String = Convert.ToBase64String(sig, 0, sig.Length);

if (isValid)
{
    // Print Signature just to confirm...
    // Here the signature validation WORKS! but I am using the private key 
}

var publicKey = (RSACryptoServiceProvider)certificate.PublicKey.Key;
bool isValid2 = publicKey.VerifyData(dataToSign, CryptoConfig.MapNameToOID("SHA256"), sig);
// isValid2 returns false. It not works with PUBLIC KEY

I have even done it this way (loading .cer file directly) and the response is the same

var 509 = new X509Certificate2(File.ReadAllBytes("certificate.cer"));
var publicKey = (RSACryptoServiceProvider)509.PublicKey.Key;
bool isValid2 = publicKey.VerifyData(dataToSign, CryptoConfig.MapNameToOID("SHA256"), sig);
// isValid2 returns false

I really appreciate your support

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
pabdat08
  • 3
  • 2

1 Answers1

0

In the link you provided the private key is implemented differently. I tested this below and VerifyData returns true. Notice the difference in the privateKey creation.

string certPath = "C:\\testing.pfx";
string certPass = "MagicPassword";

X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import(certPath, certPass, X509KeyStorageFlags.Exportable);
X509Certificate2 cert = collection[0];


RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider();
privateKey.FromXmlString(cert.PrivateKey.ToXmlString(true));

byte[] data = Encoding.UTF8.GetBytes("Hello");
byte[] signature = privateKey.SignData(data, CryptoConfig.MapNameToOID("SHA256"));
bool isValid = publicKey.VerifyData(data, CryptoConfig.MapNameToOID("SHA256"), signature);
Hyperdingo
  • 271
  • 2
  • 6