当前位置: 首页 > 知识库问答 >
问题:

如何在带有PKCS1签名的iText上签署pdf

阎弘雅
2023-03-14

我需要使用外部服务签署pdf文档,该服务将返回PKCS1签名。这意味着我必须在IExternalSignatureContainer实例中添加公钥。我使用iText 7进行整个签名过程。

在iText网站上有一个关于这种方法的很好的例子

我在一个文件中创建了整个演唱过程的示例。必需的引用:

    null

示例代码(为控制台应用程序准备好的一个文件中的两个类):

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.X509;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;

namespace SignExternalTestManuel
{
    class Program
    {
        public static void Main(String[] args)
        {
            string filePath = @"c:\temp\pdfsign\";
            string pdfToSign = Path.Combine(filePath, @"test.pdf");
            string destinationFile = Path.Combine(filePath, "test_signed.pdf");
            string userCertificatePublicKey = Path.Combine(filePath, "BITSignTestManuel5Base64.cer");
            string caCertificatePublicKey = Path.Combine(filePath, "BITRoot5Base64.cer");
            string privateKeyFile = Path.Combine(filePath, "BITSignTestManuel5.pfx");
            string privateKeyPassword =  "test";

            PdfReader reader = new PdfReader(pdfToSign);
            using (FileStream os = new FileStream(destinationFile, FileMode.OpenOrCreate))
            {
                StampingProperties stampingProperties = new StampingProperties();
                //For any signature in the Pdf  but the first one, you need to use appendMode
                //        stampingProperties.useAppendMode();
                stampingProperties.UseAppendMode();
                PdfSigner pdfSigner = new PdfSigner(reader, os, stampingProperties);
                pdfSigner.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED);

                IExternalSignatureContainer external = new GsSignatureContainer(
                    PdfName.Adobe_PPKLite,
                    PdfName.Adbe_pkcs7_detached,
                    userCertificatePublicKey,
                    caCertificatePublicKey,
                    privateKeyFile,
                    privateKeyPassword);
                pdfSigner.SignExternalContainer(external, 32000);
            }

        }
    }
    public class GsSignatureContainer : IExternalSignatureContainer
    {
        private PdfDictionary sigDic;
        private string userCertificatePublicKey;
        private string caCertificatePublicKey;
        private string privateKeyFile;
        private string privateKeyPassword;

        public GsSignatureContainer(PdfName filter, PdfName subFilter, string userCertificatePublicKey, string caCertificatePublicKey, string privateKeyFile, string privateKeyPassword)
        {
            sigDic = new PdfDictionary();
            sigDic.Put(PdfName.Filter, filter);
            sigDic.Put(PdfName.SubFilter, subFilter);
            this.userCertificatePublicKey = userCertificatePublicKey;
            this.caCertificatePublicKey = caCertificatePublicKey;
            this.privateKeyFile = privateKeyFile;
            this.privateKeyPassword = privateKeyPassword;
        }

        /// <summary>
        /// Implementation based on https://kb.itextpdf.com/home/it7kb/examples/how-to-use-a-digital-signing-service-dss-such-as-globalsign-with-itext-7#HowtouseaDigitalSigningService(DSS)suchasGlobalSign,withiText7-Examplecode
        /// </summary>
        /// <param name="pdfStream"></param>
        /// <returns></returns>
        public byte[] Sign(Stream pdfStream)
        {
            //Create the certificate chaing since the signature is just a PKCS1, the certificates must be added to the signature
            string cert = System.IO.File.ReadAllText(userCertificatePublicKey);
            string ca = System.IO.File.ReadAllText(caCertificatePublicKey);
            X509Certificate[] chain = CreateChain(cert, ca);

            String hashAlgorithm = DigestAlgorithms.SHA256;
            PdfPKCS7 pkcs7Signature = new PdfPKCS7(null, chain, hashAlgorithm, false);

            //Create the hash of of the pdf document
            byte[] hash = DigestAlgorithms.Digest(pdfStream, DigestAlgorithms.GetMessageDigest(hashAlgorithm));


            //TODO: Unclear whether i need to use this. It is from the example, but maybe only required for 
            //byte[] sh = pkcs7Signature.GetAuthenticatedAttributeBytes(hash, null, null, PdfSigner.CryptoStandard.CMS);
            //using (SHA256 sha256 = SHA256.Create())
            //{
            //    sh = sha256.ComputeHash(hash);
            //}

            //Create the actual signautre (This will be done via Service)
            byte[] signature = CreateSignature(hash, privateKeyFile, privateKeyPassword);

            pkcs7Signature.SetExternalDigest(signature, null, "RSA");

            return pkcs7Signature.GetEncodedPKCS7(hash, null, null, null, PdfSigner.CryptoStandard.CMS);
        }

        public void ModifySigningDictionary(PdfDictionary signDic)
        {
            signDic.PutAll(sigDic);
        }

        private static X509Certificate[] CreateChain(String cert, String ca)
        {
            //Note: The root certificate could be omitted and it would still work
            X509Certificate[] chainy = new X509Certificate[2];
            X509CertificateParser parser = new X509CertificateParser();
            chainy[0] = new X509Certificate(parser.ReadCertificate(Encoding.UTF8.GetBytes(cert))
                .CertificateStructure);
            chainy[1] = new X509Certificate(parser.ReadCertificate(Encoding.UTF8.GetBytes(ca))
                .CertificateStructure);
            return chainy;
        }

        #region "Create signature, will be done by an actual service"
        private byte[] CreateSignature(byte[] hash, string privateKeyFile, string privateKeyPassword)
        {
            X509Certificate2 rootCertificateWithPrivateKey = new X509Certificate2();
            byte[] rawData = System.IO.File.ReadAllBytes(privateKeyFile);
            rootCertificateWithPrivateKey.Import(rawData, privateKeyPassword, X509KeyStorageFlags.Exportable);
            using (var key = rootCertificateWithPrivateKey.GetRSAPrivateKey())
            {
                return key.SignData(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            }
        }

        #endregion


    }
}

共有1个答案

长孙玉泽
2023-03-14

我想我在我的代码中发现了问题。我没有使用GetAuthenticateDatTributeBytes直接对哈希值进行签名。只要我添加以下代码,然后对sh而不是hash签名,签名就会变得有效:

            //Create the hash based on the document hash which is suitable for pdf siging
            X509Certificate2 rootCertificateWithoutPrivateKey = new X509Certificate2();
            rootCertificateWithoutPrivateKey.Import(caCertificatePublicKey);
            X509Certificate rootCertBouncy = DotNetUtilities.FromX509Certificate(rootCertificateWithoutPrivateKey);
            List<X509Certificate> c = new List<X509Certificate>();
            c.Add(rootCertBouncy);
            PdfPKCS7 sgn = new PdfPKCS7(null, c.ToArray(), hashAlgorithm, false);
            byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, null, null, PdfSigner.CryptoStandard.CMS);
 类似资料:
  • 作为我对客户机/服务器pdf签名研究的一部分,我测试了itext pdf延迟签名示例。不幸的是,我得到的合并空签名pdf和哈希值的pdf ie输出显示无效签名。 下面是我的代码片段 我正在使用pkcss11 usb令牌进行签名

  • 我已经玩弄了一段时间的iTextSharp 5.5.7,找不到正确的方法从智能卡为PDF制作一个有效的数字签名-Adobe Reader总是说它的签名人和未知,并且不能解码签名的DER数据。 我查看了Makesignature.cs代码以供参考,以及is的功能: 然后,根据iExternalSignature.cs中的“Sign”方法 “@param message要进行散列和签名的邮件” 所以我

  • 我必须从PDF签名文档中提取签名字段,以创建打印签名版本。到目前为止,我已经能够使用以下iText代码恢复签名者证书、原因、签名日期和其他字段: 据我所知,PDF签名是使用iText PdfPkcs7类制作的,使用setExternalDigest方法添加在外部应用程序中创建的PKCS1字节数组。文件看起来已由外部工具正确签名和验证。 但是,打印版本所需的字段之一是“签名数字戳”,它是签名文档哈希

  • 我正在使用瑞士电信数字签名服务,我们有一个测试帐户。服务需要散列码pdf文件。我们把它和 数字签名(PKCS#7-延迟签名)/自应用签名以来文档已被更改或损坏 我的回应是sha256被加密了。我正在使用iText和C#来签署pdf文件。我签字,我看到一些细节(如原因,地点等)。 下面是创建带有签名字段的pdf文件的方法 我错过了什么或者做错了什么?

  • 我试图在C#中使用Bouncy Castle实现ECDSA签名算法对证书请求(CSR)的延迟签名。到目前为止,我已经设法用RSA实现了这一点,但没有用ECDSA实现。我使用来自Bouncy Castle的Pkcs10CertificationRequestDelaySigned类。 验证签名时失败的测试代码片段(完整代码如下所示): DelayCsrProvider将接收到的签名插入CSR,从而创

  • 我需要使用256位的私钥为ECDSA的256位散列签名,就像比特币一样。由于缺少python中的ECDSA文档,我感到绝望。 我在网上找到了很多代码,但是没有什么比或类似的,我发现的所有东西都是我不懂的大量数学代码,但他们使用ecdsa库(我不知道为什么他们不在一个库中添加一个用于签名的签名函数,而是在使用库时需要一页代码?)。 这是目前为止我找到的最好的代码: 但我就是不能相信这样的代码,因为我