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 removed

  • Anonymous
    May 18, 2009
    The comment has been removed

  • Anonymous
    May 21, 2009
    I tend to use the console in my sample code since it doesn't require any additional dependencies. -Shawn

  • Anonymous
    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. -Shawn

  • Anonymous
    June 28, 2009
    The comment has been removed

  • Anonymous
    January 12, 2010
    The comment has been removed

  • Anonymous
    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). -Shawn

  • Anonymous
    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. Chris

  • Anonymous
    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 removed

  • Anonymous
    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? Marcel

  • Anonymous
    February 16, 2014
    Hi,

  1. 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?
  2. Can same thing work in windows phone 8?