2016-11-21 7 views
1

전자 서명을 기존 PDF에 추가하는 데 필요한 개념 증명 데모를 작성하고 있습니다. 나는 내가 얻지 못하는 이상한 문제를 겪고있다. 일부 문서에 서명을 추가하면 다른 문서에 서명을 추가해도 작동하지 않으며 Adobe Reader에서 열 수없는 손상된 파일이 생성되는 것 같습니다. 기존 PDF 문서에 서명 할 때 종종 손상된 파일이 발생합니다.

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 파일이나 위의 프로그램에 대해 뭔가 있습니까?

답변

0

문제는 더 정확히 PdfWorker.Sign 방법, 프로그램에 : 여기

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

가 먼저 목적지에 서명 한 다음에 PdfSigner 출력을 추가 할 파일을 복사합니다.

그러나 PdfSigner 출력은 완전한 개의 서명이있는 PDF, 즉 원본과 서명이 추가 된 추가 버전입니다. 따라서 대상 파일에는 결국 두 개의 복사본이 있고 원본 복사본이 하나만 있다고 가정하여 일부 서명 추가가 생성됩니다.

이 문제를 해결하려면 File.Copy(_source, _dest, true) 작업을 제거하고 FileStreamFileMode.Append으로 열지 마십시오. 샘플 파일 "Infile2.pdf"를 서명하는 동안


심지어이 보정 한 후, 영업 이익의 샘플 파일 "Infile1.PDF"의 서명은 여전히 ​​깨진 PDF를 생성 이제 성공합니다. 그 원인은 this answer에 설명되어있는 iText 7.0.0 버그입니다 (나는 알 수있는 한) 7.0.1에서 수정되었습니다. "Infile1.PDF"는 "Infile2.pdf"가 아닌 객체 스트림을 사용하므로 이전 파일 만 영향을받습니다.

+0

File.Copy (...)로 줄 주석 처리를 시도했지만 출력 파일을 열려고 할 때 여전히 동일한 오류가 발생합니다. 파일을 복사 한 이유는 원본 파일이 변경 되었기 때문에 내가 원하지 않는 것으로 생각하기 때문입니다. 또한 나는 임시 파일을 만들고 싶지 않았고 마침내 최종 문서가 내가 본 한 예에서 완성 된 것처럼 마침내 완성되었다. – rbadi76

+0

* 출력 파일을 열려고해도 동일한 오류가 발생합니다. * - 해당 파일도 공유하십시오. 다른 이유로 동일한 오류가 표시 될 수 있습니다. – mkl

+0

@ rbadi76 아, 한 가지 추가 사항은'FileStream'을'FileMode.Append'로 열지 마십시오 :'PdfSigner' 출력을 아무 것도 추가하지 않으려는 것입니다. ... – mkl