问题
The following function uses a certificate to sign and verify.
private static bool Sign_Verify(X509Certificate2 x509, byte[] random_data)
{
//
// Local variable definitions
//
bool isVerified = false;
byte[] buffer = Encoding.Default.GetBytes("Hello World ... !");
byte[] signature_Data = null;
byte[] signature_Hash = null;
//
// Retrieve the private key of the certificate selected.
//
RSACryptoServiceProvider privateKey
= x509.PrivateKey as RSACryptoServiceProvider;
if (null == privateKey)
{
Console.WriteLine("Invalid Private Key");
} // if
else
{
Console.WriteLine("Certificate has private key.");
} // else
HashAlgorithm hashAlgo = HashAlgorithm.Create("SHA256");
byte[] hash = hashAlgo.ComputeHash(random_data);
//
// Perform signing using the private key
try
{
signature_Hash = privateKey.SignHash(
hash,
CryptoConfig.MapNameToOID("SHA256"));
if (null == signature_Hash)
{
Console.WriteLine("Error: SignHash\n\n");
} // if
else
{
Console.WriteLine("Signature_Hash generated......\n\n");
} // else
} // try
catch (CryptographicException)
{
//e.StackTrace();
} // catch
//
// Retrieve the public key of the certificate selected.
//
RSACryptoServiceProvider publicKey
= x509.PublicKey.Key as RSACryptoServiceProvider;
if (null == publicKey)
{
Console.WriteLine("Invalid Public Key");
} // if
else
{
Console.WriteLine("Certificate has public key.");
} // else
isVerified = publicKey.VerifyHash(
hash,
CryptoConfig.MapNameToOID("SHA256"),
signature_Hash);
if (false == isVerified)
{
Console.WriteLine("Signature of Hash verification failed.");
} // if
else
{
Console.WriteLine("Signature of Hash verified successfully.");
} // else
return isVerified;
} // Sign_Verify
In the HashAlgorithm.Create("SHA256"); , we are hard coding the name of signature hash algorithm. How to get the name of the signature hash algorithm of the certificate instead of hard coding it?
回答1:
It seems that there is no easy way to get signature hash algorithm from certificate in .NET. What you can do is first get signature algorithm OID
cert.SignatureAlgorithm.Value;
Then you need to somehow map this OID (this can be for example SHA256 with RSA encryption) to OID or name of just hash algorithm, without encryption (just SHA256). You can either build such map yourself, or use existing maps, for example Bouncy Castle library has one. Unfortunately it contains it in internal class, so you will have to use some reflection to get to it. So add reference to Bouncy Castle first (via nuget), then:
var mapField = typeof(Org.BouncyCastle.Cms.CmsSignedData).Assembly.GetType("Org.BouncyCastle.Cms.CmsSignedHelper").GetField("digestAlgs", BindingFlags.Static | BindingFlags.NonPublic);
var map = (System.Collections.IDictionary) mapField.GetValue(null);
This will grab value of private digestAlgs field of internal CmsSignedHelper class, which contains just the map you need.
Then you do:
var hashAlgName = (string)map[cert.SignatureAlgorithm.Value];// returns "SHA256" for OID of sha256 with RSA.
var hashAlg = HashAlgorithm.Create(hashAlgName); // your SHA256
来源:https://stackoverflow.com/questions/36277604/how-to-retrieve-the-signature-hash-algorithm-friendly-name-using-c-sharp-cryptog