Using RSACryptoServiceProvider for RSA-SHA256 signatures
Earlier this month, we released .NET 3.5 SP 1. One of the new features available in this update is that RSACryptoServiceProvider has gained the ability to create and verify RSA-SHA256 signatures.
Since RSACryptoServiceProvider relies on the underlying CAPI APIs to do its work, this feature will only be enabled on versions of Windows which support SHA-256 algorithms in CAPI. At this point, that translates to Windows Server 2003 and higher.
The code to create and verify a signature is basically the same as it was for doing RSA-SHA1:
byte[] data = new byte[] { 0, 1, 2, 3, 4, 5 };using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()){ byte[] signature = rsa.SignData(data, "SHA256"); if (rsa.VerifyData(data, "SHA256", signature)) { Console.WriteLine("RSA-SHA256 signature verified"); } else { Console.WriteLine("RSA-SHA256 signature failed to verify"); }}
The second parameter should be either the string "SHA256", the type of the SHA256Managed object, or an instance of a SHA256Managed object.
Note that this means, somewhat counter-intuitively, that passing either the type of or an instance of the SHA256CryptoServiceProvider object will not work. If you do use the SHA256CryptoServiceProvider type, you'll end up with an error like this:
Unhandled Exception: System.ArgumentException: Value was invalid. at System.Security.Cryptography.Utils.ObjToOidValue(Object hashAlg) at System.Security.Cryptography.RSACryptoServiceProvider.SignData(Byte[] buffer, Object halg)
The reason for this is the same reason that CryptoConfig does not understand SHA256CryptoServiceProvider - it was added as part of the green bits in .NET 3.5, and due to layering restrictions the red bits (such as mscorlib.dll where RSACryptoServiceProvider lives) does not know about its existence.
Also note that this functionality was added only to the RSACryptoServiceProvider type, so upstack functionality such as XML digital signatures are not yet enabled for RSA-SHA256 digital signatures. However, this does provide the base building block for those upstack crypto technologies, so that they can begin adding support in the future.
Comments
Anonymous
April 30, 2009
The comment has been removedAnonymous
May 18, 2009
The comment has been removedAnonymous
May 21, 2009
I tend to use the console in my sample code since it doesn't require any additional dependencies. -ShawnAnonymous
May 21, 2009
You need to make sure that the RSA key is stored in the PROV_RSA_AES crypto service provider. If your certificate is using PROV_RSA_FULL, then that CSP doesn't understand SHA-256, and the signature process won't work. -ShawnAnonymous
June 28, 2009
The comment has been removedAnonymous
January 12, 2010
The comment has been removedAnonymous
January 13, 2010
Hi Chris, No - Windows XP is older than Windows 2003, so it is not supported. (Windows XP is Windows version 5.1, while Windows 2003 is 5.2). -ShawnAnonymous
January 14, 2010
Hi Shawn, Interesting - thanks for the clarification about XP vs. 2003. I guess I'll have to try to find some 3rd party SHA256 libraries. ChrisAnonymous
March 03, 2010
Shawn, It seems to me what you said here is conflicting with what's stated here: http://technet.microsoft.com/en-us/library/cc750357(printer).aspx "Microsoft .NET Framework applications (i.e. Microsoft ASP.NET) only allow algorithm implementations that are allowewd by FIPS 140, meaning only classes that end in "CryptoServiceProvider" or "Cng" can be used. Any attempt to create an instance of other cryptographic algorithm classes or create instances that use non-allowed algorithms will cause an InvalidOperationException exception. " Therefore, we are not supposed to use SHA256Managed in SignData()?Anonymous
March 05, 2010
The comment has been removedAnonymous
July 29, 2011
One way around the issue Balasz mentioned here with respect to PROV_RSA_FULL certificates that do not support SHA256 signing, could be to create a new RSACryptoServiceProvider (defaults to PROV_RSA_AES as from .NET 3.5 SP1 on) and pass an argument of type CspParameters to the CSP's constructor, which points to the original key container: // Use Case: Certificate uses PROV_RSA_FULL RSACryptoServiceProvider rsaCSP = (RSACryptoServiceProvider)selectedCertificate.PrivateKey; CspParameters cspParameters = new CspParameters(); cspParameters.KeyContainerName = rsaCSP.CspKeyContainerInfo.KeyContainerName; cspParameters.KeyNumber = rsaCSP.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2; // As of .NET 3.5 SP1 the CSP instance works with a provider of type PROV_RSA_AES RSACryptoServiceProvider rsaAesCSP = new RSACryptoServiceProvider(cspParameters); rsaAesCSP.PersistKeyInCsp = false; // Now you can call SignData() in conjunction with SHA256 (even with a key marked as non-exportable) Are there any side-effects to this workaround? MarcelAnonymous
February 16, 2014
Hi,
- byte[] signature = rsa.SignData(data, "SHA256"); In this "SHA256" is merely a string.It has nothing to do with ACTUAL SHA256 alogorithm. Is it right?
- Can same thing work in windows phone 8?