26

Here is my code.

X509Certificate pXCert = new X509Certificate2(@"keyStore.p12", "password");
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;
string id = CryptoConfig.MapNameToOID("SHA256");
return csp.SignData(File.ReadAllBytes(filePath), id);

On the last line I'm getting the exception:

System.Security.Cryptography.CryptographicException "Invalid algorithm specified."

What am I doing wrong?

UPDATE:

id = 2.16.840.1.101.3.4.2.1

scott
  • 2,991
  • 5
  • 36
  • 47
  • I updated the question with the value of id. – scott Sep 15 '11 at 15:09
  • 6
    try to use pXCert.GetRSAPrivateKey() instead – thangcao Jul 28 '20 at 04:28
  • 1
    yes @thangcao, lifesaver comment! I'll also add that now in 2020, for .NET 4.6 and up, RSA itself supports SignData, like so: ((RSA)cert.GetRSAPrivateKey()).SignData(bytes, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1) – oflahero Dec 11 '20 at 12:54

8 Answers8

18

For dot net framework 4.7.0 or higher is not taking the sha1 so configure the below in application start. it's worked fine for me.

 AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
 AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
abatishchev
  • 98,240
  • 88
  • 296
  • 433
alwayssai
  • 181
  • 1
  • 3
16

There is no issue with .NET code or the CSP code you provided.

Your problem is that CSP just doesn’t support SHA 256. You can get further information here

Patrick Desjardins
  • 136,852
  • 88
  • 292
  • 341
  • Is there any way to make this work? I'm porting this from java and it needs to use the same algorithms. As far as I can tell it is using rsa + sha – scott Sep 15 '11 at 15:37
  • You may want to check http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256.aspx that is a SHA256 class in .Net Framework. But, I haven't used it. – Patrick Desjardins Sep 15 '11 at 15:49
  • The SHA256CryptoServiceProvider doesn't accept an Asymetrical key – scott Sep 15 '11 at 17:14
  • This release supports SHA-256 only for symmetric key usages, such as Kerberos keys, and where an X.509 certificate is not used to sign the message. WCF does not support RSA signatures (used in X.509 certificates) using SHA-256 hash due to the current lack of support for RSA-SHA256 in the .NET Framework 3.0 (Source : http://msdn.microsoft.com/en-us/library/aa738624.aspx) – Patrick Desjardins Sep 15 '11 at 17:25
  • thanks for you help. I'm not using this with WCF. I just want to sign a file. – scott Sep 15 '11 at 17:36
  • 2
    http://hintdesk.com/c-how-to-fix-invalid-algorithm-specified-when-signing-with-sha256/ – Gonzalo Gallotti Feb 06 '13 at 17:03
  • I was able to resolve the issue by not passing in any CspParameters when creating a new instance of RSACryptoServiceProvider. – Nathan Moinvaziri Jul 13 '16 at 18:21
12

Note that I use SHA512 but SHA256 will work with the below examples:

"Invalid algorithm specified" Took me forever to figure out and I tried practically everything.

Step 1 - the certificate has to be SHA512 and use a CSP (Cryptographic Service Provider) that is SHA512 Capable. Here is a list of CSPs and their capabilities. If you look for SHA512 you'll find the "Microsoft Enhanced RSA and AES Cryptographic Provider". By default generating certificates don't use this (at least in Windows) so you have to specify it when you create the certificate.

If you create the certificate with openssl, you can use the option -CSP below to set the correct CSP that will make it work. If you have an existing pfx, you can convert it to a PEM file with openssl, and then back to a pfx to add the option.

Create private key and certificate - this step will ask you questions, state, region etc etc.

openssl req -x509 -nodes -sha512 -newkey rsa:2048 -keyout 512key.pem -out 512cert.pem -days 3650

Create PFX file to import into your certificate store using the Microsoft Enhanced RSA and AES Cryptographic Provider:

openssl pkcs12 –export –in 512cert.pem –inkey 512key.pem –CSP “Microsoft Enhanced RSA and AES Cryptographic Provider” –out 512pfx.pfx

Step 2 : Props to Gonzalo Gallotti for posting the link to the piece of code that helped me. I commented up my code to show what each step is doing. NOTE: this code won't work without a properly generated certificate as described in step 1

public void GetCertificate() {
    
    // Get the Machine Cert Store
    var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

    string alg = CryptoConfig.MapNameToOID("SHA512");

    // Open the cert store
    store.Open(OpenFlags.ReadWrite);

    // Loop through each certificate within the store
    foreach (X509Certificate2 myCert in store.Certificates)
    {
        // Get the certificate we are looking for
        if (myCert.IssuerName.Name.Contains("CN=YourSite"))
        {
            // Check if the certificate has a private key
            if (myCert.HasPrivateKey)
            {
                // Get your custom signature as a string
                string mySignature = GetSignatureString();

                // Convert signature to byte array
                byte[] originalData = Encoding.UTF8.GetBytes(mySignature);

                // Create RSA provider from private key
                RSACryptoServiceProvider rsaProvider = (RSACryptoServiceProvider)myCert.PrivateKey;

                // Sign the signature with SHA512
                byte[] signedSignature = signedSignature = rsaProvider.SignData(originalData, alg);

                if (rsaProvider.VerifyData(originalData, alg, signedSignature))
                {
                    // Signature is verified Do Stuff
                }
                else
                {
                    throw new Exception("The data does not match the signature.");
                }
            }
        }
    }
}
jmd
  • 877
  • 8
  • 12
cmartin
  • 2,819
  • 1
  • 26
  • 31
  • Not sure what the downvote on this was for .. It certainly helped me, thanks a lot! +1 +1 – Tjad Clark Feb 02 '18 at 10:55
  • @TjadClark The lengthy code at the start hides the last part of the answer which describes the right actions to proceed ! I'll edit to correct that – jmd Apr 30 '21 at 07:52
12

You might have come here while you are migrating your application from .NET Framework 4.7 and earlier versions to 4.7.1 or later versions.
If you are getting the exception System.Security.Cryptography.CryptographicException: Invalid algorithm specified., the reason is that default SignedXML and SignedXMS algorithms changed to SHA256 for applications that target the .NET Framework 4.7.1 and later versions (from Microsoft .NET migration guide)

In that guide you'll also find the solution:

For applications that target the .NET Framework 4.7.1 and later versions, if the use of SHA256 is undesirable, you can restore the default to SHA1 by adding the following configuration switch to the runtime section of your app config file:

<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms=true;  
                  Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms=true" />

But this may not always work, especially for web applications, as you can read in this blog post, fortunately along with the answer as well. It is only necessary to add some lines in the Application_Start

protected void Application_Start(object sender, EventArgs e)
{
   [...]
   AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
   AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
}
Yasel
  • 2,920
  • 4
  • 40
  • 48
4

Which CSP your certificate is using can be checked with certutil tool (on windows)

certutil yourCertificate.p12

enter image description here

Examples:

  • Microsoft Enhanced Cryptographic Provider v1.0 => throws error with C# 4.7 and above
  • Microsoft Enhanced RSA and AES Cryptographic Provider => works
Stef Chäser
  • 1,911
  • 18
  • 26
3

Having a similar issue but just resolved it. If you are not using X509 but just the plain RSACryptoServiceProvider to get the keys, then only SHA1 is supported.

Lord of Scripts
  • 3,579
  • 5
  • 41
  • 62
2

You can set the AppContext switches in a web config via appSettings:

<appSettings>
  <add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms" value="true" />
  <add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms" value="true" />
</appSettings>
kevinpo
  • 1,853
  • 19
  • 20
0

I fixed the issue by upgrading my dependencies.

Instead of relying on the GAC version I was previously using for years, I switched to the latest NuGet packages (v16.8.0) of:

  • Microsoft.Build.Tasks.Core
  • Microsoft.Build.Utilities.Core
  • Microsoft.Build.Framework

This fixed this issue for us.