iTextSharp-如何获取PDF内容以进行签名,然后在以后进行签名 [英] iTextSharp - How to get PDF content for signing and then sign at a later time

查看:230
本文介绍了iTextSharp-如何获取PDF内容以进行签名,然后在以后进行签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个客户端-服务器应用程序,客户端必须使用其签名对PDF文档进行签名,然后将其上传到服务器.客户端没有办法将签名嵌入到PDF中,他们只能读取原始字节并以原始字节的形式产生签名,因此任务变得很复杂.

我正在尝试实施以下工作流程:

  1. 客户端将未签名的PDF上载到服务器
  2. 服务器打开PDF,提取客户端需要签名的字节,然后将这些字节发回
  3. 客户端接收这些字节,使用客户端证书对其进行签名,然后将签名发送给服务器
  4. 服务器将收到的签名嵌入到先前收到的PDF中.

我找到了一些提取字节进行签名并将签名字节嵌入PDF的代码示例(这是我正在使用的主要示例).

问题在于此示例在一个程序中执行了所有步骤,它在获取文档哈希值之后立即嵌入了签名,而没有关闭PdfStamper.我需要的是一种在添加签名字段并获取sha.Hash之后保存文档,然后在以后的某个时间(服务器接收到计算出的签名时)打开文档并将签名值嵌入PDF的一种方法.

您能建议一种修改此代码的方法,以便步骤(2)和(4)可以独立,并且不需要共享的PdfReaderPdfStamper实例吗?

解决方案

自己弄清楚了. 指向我的这段代码

证明服务器上的进程必须是以下内容:

  • 获取未签名的PDF并添加一个空的签名字段
  • 根据文件的修改内容计算需要签名的字节
  • 将带有空签名的修改后的PDF保存到临时文件中
  • 将计算出的字节发送给客户端
  • 当客户端响应签名时,打开临时文件并将签名插入到先前创建的字段中

相关的服务器代码:

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName)
{
    using (PdfReader reader = new PdfReader(unsignedPdf))
    {
        using (FileStream os = File.OpenWrite(tempPdf))
        {
            PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
            PdfSignatureAppearance appearance = stamper.SignatureAppearance;
            appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, signatureFieldName);
            IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
            MakeSignature.SignExternalContainer(appearance, external, 8192);

            return SHA1Managed.Create().ComputeHash(appearance.GetRangeStream());
        }
    }
}
public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signedBytes)
{
    using (PdfReader reader = new PdfReader(tempPdf))
    {
        using (FileStream os = File.OpenWrite(signedPdf))
        {
            IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes);
            MakeSignature.SignDeferred(reader, signatureFieldName, os, external);
        }
    }
}

private class MyExternalSignatureContainer : IExternalSignatureContainer
{
    private readonly byte[] signedBytes;

    public MyExternalSignatureContainer(byte[] signedBytes)
    {
        this.signedBytes = signedBytes;
    }

    public byte[] Sign(Stream data)
    {
        return signedBytes;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
    }
}

旁注:在所有这些iText示例中,困扰我的是没有任何注释的幻数(如此处的8192)的存在.这使得使用此库比原来要困难和烦人得多.

I'm developing a client-server application where clients have to sign PDF documents using their signatures and upload them to the server. The task is complicated by the fact that clients don't have the means to embed signatures into PDFs, they can only read raw bytes and produce the signature in the form of raw bytes.

I'm trying to implement the following workflow:

  1. The client uploads the unsigned PDF to the server
  2. The server opens the PDF, extracts the bytes that the client needs to sign, and sends those bytes back
  3. The client receives these bytes, signs them using a client certificate and sends the signature to the server
  4. The server embeds the received signature into the PDF it received earlier.

I found some code samples of extracting bytes to sign and embedding the signature bytes into the PDF (this is the main sample I'm using).

The problem is that this sample performs all the steps in one program, it embeds the signature right after getting the document hash without closing PdfStamper. What I need is some way to save the document after adding the signature field and getting sha.Hash, and then at some later time (when the server receives the computed signature) open the document and embed the signature value into the PDF.

Can you suggest a way to modify this code so that the steps (2) and (4) can be independent, and not require shared instances of PdfReader and PdfStamper?

解决方案

Figured it out myself. This piece of code pointed me to the right direction.

Turns out the process on the server has to be the following:

  • Take the unsigned PDF and add an empty signature field
  • Compute the bytes that need to be signed based on the modified content of the file
  • Save the modified PDF with an empty signature into a temporary file
  • Send the computed bytes to the client
  • When the client responds with the signature, open the temporary file and insert the signature into the field created earlier

The relevant server code:

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName)
{
    using (PdfReader reader = new PdfReader(unsignedPdf))
    {
        using (FileStream os = File.OpenWrite(tempPdf))
        {
            PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
            PdfSignatureAppearance appearance = stamper.SignatureAppearance;
            appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, signatureFieldName);
            IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
            MakeSignature.SignExternalContainer(appearance, external, 8192);

            return SHA1Managed.Create().ComputeHash(appearance.GetRangeStream());
        }
    }
}
public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signedBytes)
{
    using (PdfReader reader = new PdfReader(tempPdf))
    {
        using (FileStream os = File.OpenWrite(signedPdf))
        {
            IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes);
            MakeSignature.SignDeferred(reader, signatureFieldName, os, external);
        }
    }
}

private class MyExternalSignatureContainer : IExternalSignatureContainer
{
    private readonly byte[] signedBytes;

    public MyExternalSignatureContainer(byte[] signedBytes)
    {
        this.signedBytes = signedBytes;
    }

    public byte[] Sign(Stream data)
    {
        return signedBytes;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
    }
}

Side note: what bothers me in all those iText samples is the presence of magic numbers (like 8192 here) without any comments. This makes using this library so much more difficult and annoying than it could be.

这篇关于iTextSharp-如何获取PDF内容以进行签名,然后在以后进行签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆