【问题标题】:"ERROR unspecified algorithm" when signing a PDF with itextsharp 5.5.13.2 and SHA-256使用 itextsharp 5.5.13.2 和 SHA-256 签署 PDF 时出现“错误未指定算法”
【发布时间】:2021-09-06 09:05:09
【问题描述】:

早上好,我正在尝试使用 ItextSharp 5.5.13.2 和 SHA-256 对 PDF 文档进行签名,但在签名时我收到错误“指定的算法无效”。当我使用带有 .NetFramework 4.7.2 的 SHA-1 来签署 PDF 时,不会发生此错误,下一种方法是我用来签署 PDF 的方法。

    public void SignPDF(string PathSourceDoc, string PathTargetDoc, X509Certificate2 certificate, string pathLogo)
    {
        using (PdfReader reader = new PdfReader(PathSourceDoc))
        using (var writer = new FileStream(PathTargetDoc, FileMode.Create, FileAccess.Write))
        using (var stamper = PdfStamper.CreateSignature(reader, writer, '\0', null, true))
        {


            var signature = stamper.SignatureAppearance;
            signature.CertificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;
            signature.Reason = "My Reason";
            signature.Location = "My Location";
            signature.SignDate = DateTime.Now;
            signature.Acro6Layers = true;

            PdfSignature objSignature = new PdfSignature(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
            objSignature.Date = new PdfDate(signature.SignDate);
            signature.CryptoDictionary = objSignature;

            var bcCert = DotNetUtilities.FromX509Certificate(certificate);
            string name = CertificateInfo.GetSubjectFields(bcCert).GetField("CN");
            string industry = CertificateInfo.GetSubjectFields(bcCert).GetField("O");
            string position = CertificateInfo.GetSubjectFields(bcCert).GetField("T");
            DateTime date = DateTime.Now;

            signature.Layer2Text = "Digital Signed by: " + name + "\n" +
                                   "Reason: " + "My Reason" + "\n" +
                                   "Date: " + date;
            signature.Layer2Font = new Font(iTextSharp.text.Font.FontFamily.TIMES_ROMAN, 8);

            Image img = Image.GetInstance(pathLogo);
            signature.SignatureGraphic = img;

            signature.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION;
            Rectangle rect = new Rectangle(50, 50, 300, 110);
            signature.SetVisibleSignature(rect, 1, null);
            var standard = CryptoStandard.CADES;

            /*I tried this way but I get an error of type Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'The requested operation is not supported.'*/
            X509Certificate cert = certificate;
            X509Certificate2 signatureCert = new X509Certificate2(cert);
            var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signatureCert.PrivateKey).Private;// the error is generated in this line (Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'The requested operation is not supported.').
            IExternalSignature es = new PrivateKeySignature(pk, "SHA-256");
            /****************************************************************************************************************************************************************/

            X509Certificate2Signature externalSignature = new X509Certificate2Signature(certificate, DigestAlgorithms.SHA1); /*throws an exception on this line of type "System.ArgumentException: 'Unknown encryption algorithm System.Security.Cryptography.RSACng'" 
                                                                                                                              * when using .NET Core 3.1. this always happens, it doesn't matter if I use sha1 or use any other algorithm, it always generates error*/


            MakeSignature.SignDetached(signature, externalSignature, new[] { bcCert }, null, null, null, 0, standard);
        }
    }

该方法接收我需要签名的 PDF 的路径、签名时将创建的 pdf 的路径、证书和用于在签名中显示图像的徽标的路径作为输入参数。实际上我不知道我做错了什么,因为我一直在研究相关问题,它应该适用于 SHA-1 和 SHA-256 以及 .NetFramework。

然后我将项目迁移到 .NetCore 3.1 以尝试解决问题,但我得到了一个新错误(代码中已对此进行了注释)。我的目标是使用 .NetCore 并允许我使用 sha256 签署 pdf。为了使程序正常工作,我修改 SignPdf 方法没有问题。 任何贡献或信息链接表示赞赏。感谢您的帮助。

Psdt:这是stacktrace如下...

这是项目迁移到.Net Core 3.1 时出现错误的stacktrace图片

【问题讨论】:

  • 您的私钥支持哪些签名算法?请分享完整的堆栈跟踪。
  • 您好@mkl,非常感谢您的帮助,我编辑了添加堆栈跟踪的问题,密钥支持的算法是“sha256RSA”,签名哈希算法是“sha256”。我直接从我使用的证书中获得了这些信息,程序在生成 MakeSignature.SignDetached 的行中抛出错误
  • @mkl 我编辑了这个问题,这是你要求的吗?
  • 是的。但这让我很困惑。 X509Certificate2Signature.Sign"SHA256" 调用 RSACryptoServiceProvider.SignData。 Microsoft 加密 API 的该方法显然确实知道该算法,因为在将调用转发到 RSACryptoServiceProvider.SignHash(发生异常的地方)之前,它必须计算哈希值。但是,在将计算得到的哈希转发到RSACryptoServiceProvider.SignHash 之后,Microsoft 加密 API 的这种方法显然知道该算法。嗯,但这似乎确实有记录。
  • @mkl 我将程序从 .Net Framework 4.7.2 迁移到 .Net Core 3.1 以查看是否可以通过这种方式解决问题(我编辑了问题代码并添加了新的错误调用堆栈)但现在我遇到了一个问题,它不允许我使用任何算法签名,并最终在 X509Certificate2Signature 对象的行中生成错误,接收到类型为“System.ArgumentException:'未知加密算法 System.Security.Cryptography。 RSACng'”。有没有办法使用 sha256 和 .NetCore 3.1 进行签名?顺便感谢您的帮助。

标签: pdf itext signature sha1 sha256


【解决方案1】:

X509Certificate2Signature 使用的 Microsoft Crypto API 显然不支持 SHA-256。

您将X509Certificate2Signature 实例用作MakeSignature.SignDetachedIExternalSignature 参数。

如果您的X509Certificate2PrivateKeyRSACryptoServiceProvider(您的证书似乎就是这种情况),则X509Certificate2Signature.Sign 调用

RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)certificate.PrivateKey;
return rsa.SignData(message, hashAlgorithm);

RSACryptoServiceProvider.SignData 起初显然确实支持"SHA256",因为在将执行转发到SignHash 之前,它必须计算要签名的哈希值。

不过,RSACryptoServiceProvider.SignHash 不支持 SHA-256,根据该方法的 Microsoft docs

备注

此方法创建一个使用 VerifyHash 方法验证的数字签名。

有效的哈希算法是 SHA1 和 MD5。算法标识符可以通过使用 MapNameToOID 方法从哈希名称中导出。

由于 SHA1 和 MD5 的冲突问题,Microsoft 建议使用基于 SHA256 或更好的安全模型。

(查看时间:2021-06-24,11:07)

因此,您会收到 “指定算法无效” 错误。

因此,基本上,人们不应再基于RSACryptoServiceProvider 进行RSA 签名的IExternalSignature 实现。

也许这就是为什么 X509Certificate2Signature 没有移植到 iText 版本 7...

另一种方法可能是首先检查PrivateKey 是否为RSACng,在这种情况下将其用作RSACng。 RSA 算法的这种下一代加密技术 (CNG) 实现应该支持更好的散列算法...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    • 2015-03-18
    • 2017-02-24
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多