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");




        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 (12)

  1. Balazs says:

    Could you tell me, why an actually existing private key wont’t work with this method (on any current OS)

    X509Store _windowsStore = new X509Store( StoreName.My , StoreLocation.CurrentUser );

    _windowsStore.Open(OpenFlags.MaxAllowed); // for the sake of testing

    X509Certificate2 _cachedCert = _windowsStore.Certificates[0];

    RSACryptoServiceProvider _provider = null;

    byte[] data = new byte[] { 0, 1, 2, 3, 4, 5 };

    // CASE A, I’d like it to work

    if (_cachedCert.HasPrivateKey)


    _provider = (RSACryptoServiceProvider)_cachedCert.PrivateKey;

    // This will throw {System.Security.Cryptography.CryptographicException}

    // "Invalid algorithm specified.rn"

    byte[] sigedBytes = _provider.SignData(data, "SHA256");


    // CASE B, This works, this was your example

    _provider = new RSACryptoServiceProvider();

    byte[] sigedBytes2 = _provider.SignData(data, "SHA256");

  2. We can also print in a message box , why to use console ?

  3. I tend to use the console in my sample code since it doesn’t require any additional dependencies.


  4. 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.


  5. Pete R says:

    Hi Shawn,

    It seems this might still run afoul of this knowledgebase issue with regard to delays incurred while calling the SignData method: I need to sign cookies for a very high-traffic website and such delays would be unacceptable. Is there a way to do RSA-SHA256 while still avoiding this issue? Thanks!

  6. Chris K says:

    Should this code work under Windows XP (which I assume is "higher" than Server 2003)?  I have .NET 3.5 SP1 installed but get a CryptographicException "Object identifier (OID) is unknown" error on the rsa.SignData(data, "SHA256") line.  

    It works fine if I change the OID to "SHA1".

  7. 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).


  8. cmkessell says:

    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.


  9. Shicai Hu says:


    It seems to me what you said here is conflicting with what’s stated here:

    "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()?

  10. The SHA256 parameter herer will not be used to actually hash the data (if you’re calling SignHash/VerifyHash).  Instead, it’s just telling us what hash algorithm was used.  You won’t get a FIPS error unless you actually try to use SHA256Managed to hash the data or call SignData/VerifyData which will do that internally.


  11. Marcel Roma says:

    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?


  12. Vaibhav Matle says:


    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?