scott
scott

Reputation: 3081

Why am I getting "Invalid algorithm specified" exception

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

Upvotes: 30

Views: 44968

Answers (10)

NitrusCS
NitrusCS

Reputation: 763

I was able to get around the issue without rebuilding the certificate by loading the cert as exportable and then building the RSA CSP in code. (This is powershell, but C# should be similar):

$Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($pfxPath, $pfxPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$rsaCsp = New-Object System.Security.Cryptography.RSACryptoServiceProvider
$rsaParams = $Cert.PrivateKey.ExportParameters($true)
$rsaCsp.ImportParameters($rsaParams)
$signedBytes = $rsaCsp.SignData($toSign,[System.Security.Cryptography.HashAlgorithm]::Create("SHA256"))

Upvotes: 0

Will
Will

Reputation: 11

You need to use

RSA rsaKey = cert.GetRSAPrivateKey();

instead of

RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;

And further down the road when you sign the reference specify DigestMethod and SignatureMethod

            Reference reference = new Reference();
        reference.Uri = "";


        // Specify SHA-256 as the hash algorithm
        reference.DigestMethod = SignedXml.XmlDsigSHA256Url;

        signedXml.AddReference(reference);

        // Add the key info to specify the signature method
        signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA256Url;

        signedXml.ComputeSignature();

Upvotes: 1

cmartin
cmartin

Reputation: 2941

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

Upvotes: 12

Gi Beraudo
Gi Beraudo

Reputation: 1

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.

Upvotes: 0

Stef Chäser
Stef Chäser

Reputation: 2058

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

Upvotes: 4

kevinpo
kevinpo

Reputation: 1963

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>

Upvotes: 2

alwayssai
alwayssai

Reputation: 311

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

Upvotes: 21

Yasel
Yasel

Reputation: 3120

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

Upvotes: 15

Lord of Scripts
Lord of Scripts

Reputation: 3619

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.

Upvotes: 3

Patrick Desjardins
Patrick Desjardins

Reputation: 140983

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

Upvotes: 16

Related Questions