RSACryptoServiceProvider does work with SHA2-based signatures, but you have to invest some effort into it.
When you use a certificate to get your RSACryptoServiceProvider it really matters what's the underlying CryptoAPI provider. By default, when you create a certificate with 'makecert', it's "RSA-FULL" which only supports SHA1 hashes for signature. You need the new "RSA-AES" one that supports SHA2.
So, you can create your certificate with an additional option: -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" (or an equivalent -sy 24) and then your code would look like (in .NET 4.0):
var rsa = signerCertificate.PrivateKey as RSACryptoServiceProvider;
byte[] signature = rsa.SignData(data, CryptoConfig.CreateFromName("SHA256"));
If you are unable to change the way your certificate is issued, there is a semi-ligitimate workaround that is based on the fact that by default RSACryptoServiceProvider is created with support for SHA2. So, the following code would also work, but it is a bit uglier: (what this code does is it creates a new RSACryptoServiceProvider and imports the keys from the one we got from the certificate)
public string Sign(string contentForSign,string priKeyFile, string keyPwd) { var rsa = GetPrivateKey(priKeyFile,keyPwd); // Create a new RSACryptoServiceProvider var rsaClear = new RSACryptoServiceProvider(); // Export RSA parameters from 'rsa' and import them into 'rsaClear' var paras = rsa.ExportParameters(true); rsaClear.ImportParameters(paras); using (var sha256 = new SHA256CryptoServiceProvider()) { var signData = rsa.SignData(Encoding.UTF8.GetBytes(contentForSign), sha256); return BytesToHex(signData); } } public bool VerifySign(string contentForSign, string signedData,pubKeyFile) { var rsa = GetPublicKey(pubKeyFile); using (var sha256 = new SHA256CryptoServiceProvider()) { return rsa.VerifyData(Encoding.UTF8.GetBytes(contentForSign), sha256, HexToBytes(signedData)); } } /// <summary> /// 獲取簽名證書私鑰 /// </summary> /// <param name="priKeyFile"></param> /// <param name="keyPwd"></param> /// <returns></returns> private static RSACryptoServiceProvider GetPrivateKey(string priKeyFile, string keyPwd) { var pc = new X509Certificate2(priKeyFile, keyPwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); return (RSACryptoServiceProvider) pc.PrivateKey; } /// <summary> /// 獲取驗簽證書 /// </summary> /// <param name="pubKeyFile"></param> /// <returns></returns> private static RSACryptoServiceProvider GetPublicKey(string pubKeyFile) { var pc = new X509Certificate2(pubKeyFile); return (RSACryptoServiceProvider) pc.PublicKey.Key; }
public static byte[] HexToBytes(string text) { if (text.Length % 2 != 0) throw new ArgumentException("text 長度為奇數。"); List<byte> lstRet = new List<byte>(); for (int i = 0; i < text.Length; i = i + 2) { lstRet.Add(Convert.ToByte(text.Substring(i, 2), 16)); } return lstRet.ToArray(); } /// <summary> /// bytes轉換hex /// </summary> /// <param name="data">bytes</param> /// <returns>轉換後的hex字串</returns> public static string BytesToHex(byte[] data) { StringBuilder sbRet = new StringBuilder(data.Length * 2); for (int i = 0; i < data.Length; i++) { sbRet.Append(Convert.ToString(data[i], 16).PadLeft(2, '0')); } return sbRet.ToString(); }
https://stackoverflow.com/questions/10673146/signature-with-sha256