jruizaranguren jruizaranguren - 15 days ago 9
C# Question

CryptographicException, provider type does not match registered value, when using iTextSharp and RSA and AES csp

I want to make a

PADES
signature a PDF using
SHA-256
as hash algorithm. I'm using the following code:

public static byte[] Sign(
byte[] pdfIn,
X509Certificate2 cert,
string reason,
string hashAlgorithm = DigestAlgorithms.SHA1
)
{
using (var reader = new PdfReader(pdfIn))
using (var pdfOut = new MemoryStream())
{
var stamper = PdfAStamper.CreateSignature(reader, pdfOut, '\0');

var appearance = stamper.SignatureAppearance;
appearance.Reason = reason;

var parser = new X509.X509CertificateParser();
var chain = new X509.X509Certificate[] {
parser.ReadCertificate(cert.RawData)
};

var signature = new X509Certificate2Signature(cert, hashAlgorithm);

MakeSignature.SignDetached(
appearance,
signature,
chain,
null,
null,
null,
0,
CryptoStandard.CADES
);
return pdfOut.ToArray();
}
}


I'm importing a certificate with
certutil
. If I use the following command and
SHA-1
as hashAlgorithm, it works properly:

certutil -f -user -p PASSWORD -importpfx CERT_NAME.pfx


But if I select a csp with
SHA-256
capabilities, I get a
CryptographicException, provider type does not match registered value
. The import is made through:

certutil -f -user -p PASSWORD -csp "Microsoft Enhanced RSA and AES Cryptographic Provider" -importpfx CERT_NAME.pfx


The exception is:

Result Message: System.Security.Cryptography.CryptographicException : provider type does not match registered value
Result StackTrace:
in System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
in System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
in System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
in System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
in System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
in iTextSharp.text.pdf.security.X509Certificate2Signature..ctor(X509Certificate2 certificate, String hashAlgorithm)
in PdfCommon.Pdf.Sign(Byte[] pdfIn, X509Certificate2 cert, String reason, String hashAlgorithm) in c:\Projects\svn\playground\trunk\PdfCommon\Pdf.cs:line 46
in PdfCommon.Tests.Pdf_test.Should_sign_a_pdf_with_pades_basic_profile() in c:\Projects\svn\playground\trunk\PdfCommon.Tests\Pdf_test.cs:line 54


The exception is thrown when retrieving the private key. I can reproduce the exception by accessing to
cert.PrivateKey
.

Answer

I eventually solved it by using RSACryptoServiceProvider to retrieve the private key:

    public static byte[] Sign(
        byte[] pdfIn,
        X509Certificate2 cert,
        string reason = "",
        string hashAlgorithm = DigestAlgorithms.SHA256
        )
    {
        using (var reader = new PdfReader(pdfIn))
        using (var pdfOut = new MemoryStream())
        using (var rsa = (RSACryptoServiceProvider)cert.PrivateKey)
        {
            var stamper = PdfAStamper.CreateSignature(reader, pdfOut, '\0');

            var appearance = stamper.SignatureAppearance;
            appearance.Reason = reason;

            var signature = new PrivateKeySignature(
                DotNetUtilities.GetRsaKeyPair(rsa).Private,
                hashAlgorithm);

            var parser = new X509.X509CertificateParser();
            var chain = new X509.X509Certificate[] { 
            parser.ReadCertificate(cert.RawData)
            };

            MakeSignature.SignDetached(
                appearance,
                signature,
                chain,
                null,
                null,
                null,
                0,
                CryptoStandard.CADES
                );

            return pdfOut.ToArray();
        }
    }
Comments