Reputation: 429
I need to sign and verify a string using my company's digital certificate. The VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signature); portion returns false so I get the "Signature not valid" error. What am I doing wrong? What is the most likely cause for this error?
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleApplication1
{
class Program
{
static byte[] Sign(string text, string certSubject)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
X509Certificate2 myCert = null;
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 cert in store.Certificates.Find(X509FindType.FindBySubjectName, certSubject, false))
{
myCert = cert;
break;
}
store.Close();
if (myCert == null)
{
throw new Exception("Certificate not found: " + certSubject, null);
}
// Hash the data
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
// Sign the hash
return provider.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
}
static bool Verify(string text, byte[] signature, string certPath)
{
// Load the certificate we'll use to verify the signature from a file
X509Certificate2 cert = new X509Certificate2(certPath);
// Note:
// If we want to use the client cert in an ASP.NET app, we may use something like this instead:
// X509Certificate2 cert = new X509Certificate2(Request.ClientCertificate.Certificate);
// Get its associated CSP and public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
// Hash the data
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
// Verify the signature with the hash
return csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signature);
}
static void Main(string[] args)
{
// Usage sample
try
{
// Sign text
byte[] signature = Sign("Test 123", "Ross cert");
// Verify signature.
if (Verify("Test 123", signature, @"C:\...RossTest.cer"))
{
Console.WriteLine("SUCCESS! Signature verified");
}
else
{
Console.WriteLine("ERROR: Signature not valid!");
}
}
catch (Exception ex)
{
Console.WriteLine("EXCEPTION: " + ex.Message);
}
Console.ReadKey();
}
}
}
Upvotes: 3
Views: 5182
Reputation: 27619
I would imagine that the problem is that in your sign method you go to a lot of effort to get myCert
but then never use it. You just sign it with your newly created uninitialised RSACryptoServiceProvider
.
i'd imagine that after the store.Close()
line you want something like the following:
RSACryptoServiceProvider provider = (RSACryptoServiceProvider)cert.PrivateKey;
Upvotes: 2
Reputation: 43553
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
That's the only place where provider
is assigned when you sign the data. That code means you just created a totally new keypair, i.e. it's not associated with the certificate you looked for.
When you verify the signature you're using the public key of the certificate (not the one from the key pair you generated). Since they don't match you'll never get a valid signature verification.
IOW you need to sign with the private key associated with the certificate, not just any keypair.
Upvotes: 1