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

签署现有的PDF文档有时会导致文件损坏

胡鸿羲
2023-03-14

我正在编写一个概念的演示证明,将电子签名添加到现有的pdf中。我遇到了一个奇怪的问题,我不明白。似乎将签名添加到某些文档可以正常工作,而将签名添加到其他文档则不行,并且会生成Adobe Reader无法打开的损坏文件。

这是我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using iText;
using iText.Kernel.Pdf;
using System.IO;
using iText.Layout;
using iText.Layout.Element;
using iText.Kernel.Geom;
using Org.BouncyCastle.Crypto.Tls;
using iText.Signatures;
using System.Collections.ObjectModel;
using Org.BouncyCastle.Pkcs;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Crypto;
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using iText.IO.Image;

namespace LTVSkilrikjaDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string welcomeText = "Welcome to LTVSkilríkjaDemotolid!";
            string pressEnterToTry = "Commands: 's' - sign, 'stop' - stops the programme";
            Console.WriteLine(welcomeText);
            Console.WriteLine(pressEnterToTry);

            // Base directory prepared
            string basedir = AppDomain.CurrentDomain.BaseDirectory;
            int index = basedir.IndexOf(@"bin\");
            basedir = basedir.Remove(index);

            string readString = Console.ReadLine().ToLower();

            while(!readString.Equals("stop"))
            {
                if(readString.Equals("c"))
                {
                    string inFile = "Infile2.pdf";
                    string outFile = "Outfile2.pdf";

                    // Open PDF document and decide where to write the new document
                    PdfWorker worker = new PdfWorker();
                    worker.ReadPdf(basedir + "App_Data\\InFiles\\" + inFile, basedir + "App_Data\\OutFiles\\" + outFile);

                    // Start working on certificate
                    X509Store store = new X509Store("My");

                    store.Open(OpenFlags.ReadOnly);

                    Collection<Org.BouncyCastle.X509.X509Certificate> xcertificates = new Collection<Org.BouncyCastle.X509.X509Certificate>();

                    foreach (X509Certificate2 mCert in store.Certificates)
                    {
                        if (mCert.Subject.IndexOf("CN=Róbert") > -1)
                        {
                             xcertificates.Add(Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(mCert));
                        }
                    }

                    Org.BouncyCastle.X509.X509Certificate[] certificatesProcessed = new Org.BouncyCastle.X509.X509Certificate[xcertificates.Count];
                    for(int i = 0; i < xcertificates.Count; i++)
                    {
                        certificatesProcessed[i] = xcertificates[i];
                    }

                    var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(store.Certificates[5].PrivateKey).Private;

                    try
                    {
                        worker.Sign(certificatesProcessed, pk, DigestAlgorithms.SHA1, PdfSigner.CryptoStandard.CADES, "No apparent raisin!", "Lost in Iceland", null, null, null, 0, true, basedir);
                    }
                    catch(Exception ex)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("Error! " + ex.Message + "\n\r" + ex.StackTrace);
                        if(ex.InnerException != null)
                        {
                            Console.WriteLine("Inner exception: " + ex.InnerException.Message);
                        }
                        Console.ForegroundColor = ConsoleColor.Gray;                      
                    }
                }
                else if(!readString.Equals("stop"))
                {
                    Console.WriteLine("Command not understood. Understand only 's' and 'stop'.");
                }

                readString = Console.ReadLine();
            }

            Console.WriteLine("Goodbye!");
            System.Threading.Thread.Sleep(500);

        }
    }

    public class PdfWorker
    {
        private PdfDocument _document;
        private string _source;
        private string _dest;

        public void ReadPdf(string source, string dest)
        {
            _source = source;
            _dest = dest;
        }

        public void Sign(Org.BouncyCastle.X509.X509Certificate[] chain, Org.BouncyCastle.Crypto.ICipherParameters pk,
            string digestAlgorithm, PdfSigner.CryptoStandard subfilter, string reason, 
            string location, Collection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient,
            int estimatedSize, bool initial, string baseDir)
        {
            File.Copy(_source, _dest, true);
            FileStream f = new FileStream(_dest, FileMode.Append);
            try
            {

                PdfSigner signer = new PdfSigner(new PdfReader(_source), f, true);
                _document = signer.GetDocument();
                _document.AddNewPage();

                // Work the last page
                Rectangle pageSize = _document.GetLastPage().GetPageSizeWithRotation();
                //PdfWriter w = _document.GetWriter();
                //long currentPos = w.GetCurrentPos();
                float llx = pageSize.GetWidth() - 350 - 20; //pageSize.GetWidth() / 2 - 350 / 2;
                float lly = pageSize.GetHeight() - 50 - 20; // pageSize.GetHeight() / 2 - 150 / 2;
                float urx = 350; //llx + 350;
                float ury = 50; //lly + 150;
                PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
                appearance.SetPageRect(new Rectangle(llx, lly, urx, ury));
                appearance.SetReason(reason);
                appearance.SetLocation(location);

                byte[] imagebytes = File.ReadAllBytes(baseDir + "App_Data\\UndirskriftDemo.png");
                // It is not possible to use the path as it contains Icelandic characters 
                // which itext chokes on. We use byte array instead
                ImageData imgData = ImageDataFactory.Create(imagebytes);
                Image img = new Image(imgData);
                img = img.ScaleToFit(350.0f, 50.0f);
                appearance.SetImage(imgData);

                int pageCount = _document.GetNumberOfPages();

                // Creating the appearance
                if(initial == true)
                {
                    signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
                }

                appearance.SetPageNumber(pageCount);
                Rectangle rect = new Rectangle(10, 50, 350, 50);
                appearance.SetPageRect(rect).SetPageNumber(pageCount);
                appearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION);
                signer.SetFieldName(signer.GetNewSigFieldName());

                // Creating the signature
            IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm);

                signer.SignDetached(pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);

                Console.WriteLine("Signing successful!");
            }
            catch(Exception ex)
            {
                throw ex;
            }
            finally
            {
                _document.Close();
                f.Close();
            }
        }
    }
}

请看这里的文件。Infile1.pdf我不能签名,但Infile2.pdf签名很好。Outfile1.pdf是损坏的文件。https://app.box.com/s/52jqe8qirl80km6hunxucs00dntx70o5

这是什么原因造成的?输入的PDF文件或上面的程序有什么问题吗?

共有1个答案

斜俊
2023-03-14

问题出在你的程序上,更确切地说是出在你的< code>PdfWorker上。符号方法:

File.Copy(_source, _dest, true);
FileStream f = new FileStream(_dest, FileMode.Append);
try
{
    PdfSigner signer = new PdfSigner(new PdfReader(_source), f, true);
    ...

在这里,首先复制要签名的文件到目的地,然后将< code>PdfSigner输出附加到该文件。

但是< code>PdfSigner输出是完整的签名PDF,即源代码加上添加了签名的附加修订版。因此,在目标文件中,您最终得到了源文件的两个副本,然后在假设只有源文件的一个副本在前面的情况下,生成了一些签名附加内容。

要解决此问题,只需删除文件.Copy(_source,_dest,真实)操作,并且不要打开文件流文件模式.Append.

即使在此更正之后,对OP的示例文件“Infile1.PDF”的签名仍然会创建一个损坏的PDF,而对示例文件“Infile2.pdf”的签名现在成功了。原因是这个答案中解释的iText 7.0.0错误(据我所知)在7.0.1中得到了修复。由于“Infile1.PDF”使用对象流,而“Infile2.pdf”不使用,因此只有前一个文件受到影响。

 类似资料:
  • 问题内容: 我以前使用Axios下载GET端点提供的文件。端点已更改,现在是POST,但是不需要参数。我正在更新原始的下载方法,但是返回了损坏的文件。 我不知道,如果问题出在,或如何响应的处理或全部的上方。到目前为止,我已经尝试了各种选择,但没有运气。任何建议将不胜感激! 我已经能够使用Postman下载文件,所以我知道端点提供的文件很好。我只是无法在我的React代码中理清参数来做到这一点。 问

  • 然而,我想使用相同的文件,这意味着我不再假装复制PDF了。我要抓取文档,签名,并覆盖原来的。 由于我了解到让FileInputStream和FileOutputStream指向同一个文件不是一个好主意,所以我只是尝试使用file类。 我尝试了以下操作:

  • 我可以通过外部签名使用itextpdf库对文档进行签名。 但问题是,最终用户不想发送他的文档,因为它可能包含任何敏感数据。因此,我要求最终用户给出文档哈希,以便与外部服务签署哈希,并将签署后的哈希发回。 但是,问题来了,当他们试图使用itextpdf()用给定的签名散列对文档进行签名时,PDF文档被签名了。但在验证签名时,表明签名是无效的。 因此,问题的发生是因为每次使用(itextpdf库)打开

  • 我在android和iText上遇到了一些问题,如果有人能帮忙的话。 android应用程序编写多个页面,每个页面包含不同的表。我没有允许一个表跨越一个页面,而是为每个页面添加一个表,并为下一个页面创建一个新表。这样我就可以控制页面总数、页眉和页脚。 我的问题是Android adobe pdf阅读器显示文档很好,正是我正在寻找的。但是,当我在PC上打开一个窗口以访问平板电脑上的 /mnt/sdc

  • 我正在为我的应用程序做一个PDF签名功能。以下是工作流程: PDF存储在服务器上。 我将所有必需的签名字段包含到文件中,并使用ZendPDF的扩展名为FaritPDF计算字节长度等。 我根据使用SHA256计算的字节长度计算哈希。 哈希将发送到客户端。 客户端使用PFX文件对哈希进行签名,并创建包含哈希的PKCS7对象。 将PKCS7对象发送到服务器。 PKCS7对象包含在PDF中,并呈现PDF。

  • 目标是实现一个PDF签名过程,在该过程中,服务器(.NET核心服务)根据请求(Electronic)向客户端提供要签名的散列。然后,客户端使用通过PKCS#11接口从智能卡获得的私钥对给定散列进行签名。然后将签名发送回服务器,以便使用iTextSharp将其附加到PDF文件中。 使用node-webcrypto-p11使用智能卡令牌签名哈希的过程目前非常简单(需要进行大量的尝试和错误)。采用的算法