使用 iTextSharp、RSA 和 AES csp 时,CryptographicException,提供者类型与注册值不匹配

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

我想使用 SHA-256 作为散列算法将 PADES 签名制作成 PDF。我正在使用以下代码:

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, '[=10=]');

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

我正在使用 certutil 导入证书。如果我使用以下命令并将 SHA-1 作为 hashAlgorithm,它可以正常工作:

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

但是如果我 select 具有 SHA-256 功能的 csp,我会得到 CryptographicException, provider type does not match registered value。通过以下方式导入:

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

例外情况是:

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

获取私钥时抛出异常。我可以通过访问 cert.PrivateKey.

来重现异常

我最终通过使用RSACryptoServiceProvider检索私钥解决了这个问题:

    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, '[=10=]');

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