如何使用iText7将.p7s字节数组插入PDF?

唐2

我正在尝试将.p7s字节数组信息插入签名字段,请按照下面的图像操作:

PDF文件结构图

我的步骤:

准备签名容器

原始的PDF是“ tmp / example.pdf”,而这部分的输出是“ results / prepared.pdf”

PdfSigner signer = new PdfSigner(new PdfReader("tmp/example.pdf"), new FileStream("results/prepared.pdf", FileMode.Create), new StampingProperties().UseAppendMode());
signer.SetFieldName("Signature1");

PdfDocument _pdfDocument = new PdfDocument(new PdfReader("tmp/example.pdf"));

PdfSignatureAppearance sigAppearance = signer.GetSignatureAppearance();
sigAppearance
    .SetPageRect(new Rectangle(144, 144, 200, 100))
    .SetPageNumber(1)
    .SetContact("This is contact")
    .SetReason("This is reason")
    .SetLocation("This is location")
    .SetSignatureCreator("This is signature creator");

MyExternalSignatureContainer _container = new MyExternalSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached, _chain);

IExternalSignatureContainer container = _container; 
signer.SignExternalContainer(container, 8192);
byte[] _sb = _container.Signed_Bytes;

我的外部签名容器类

public byte[] Sign(Stream data)
{
    iText.Signatures.PdfPKCS7 _sgn = new iText.Signatures.PdfPKCS7(null, chain, "SHA256", false);
    byte[] _hash = iText.Signatures.DigestAlgorithms.Digest(data, "SHA256");
    byte[] _sh = _sgn.GetAuthenticatedAttributeBytes(_hash, PdfSigner.CryptoStandard.CMS,
        null, null);

    Signed_Bytes = _sh;

    return new byte[0]; ;
}

直到这部分一切正常,我得到了“ results / prepared.pdf”哈希值,并发送给外部签名服务,并获得了.p7s

现在我想根据上面的图片将.p7s byte []插入PDF结构的签名值部分。

我尝试使用下面的代码获取“ results / prepared.pdf”PdfDictionayByteRange信息,我希望在“ results / injected.pdf”处将注入的.p7s注入“ results / prepared.pdf”的签名容器中。

PdfDocument pdfDocument = new PdfDocument(new PdfReader("results/prepared.pdf"), new PdfWriter("results/injected.pdf").SetSmartMode(true));

 SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
PdfSignature signature = signatureUtil.GetSignature("Signature1");

PdfDictionary _pd = signatureUtil.GetSignatureDictionary("Signature1");

现在,我得到了“ _pd”的结果,如下所示:

{<</ByteRange [0 107457 123843 2688 ] /ContactInfo This is contact /Contents 

我的理解(如果我错了,请纠正我)是我应该将.p7s字节数组设置为107457作为起始位置。

尝试将.p7s注入现有签名容器

我尝试在paddedSig下面制作数组并将.p7s复制到它:

byte[] _p7s = System.IO.File.ReadAllBytes("tmp/example.p7s");
byte[] paddedSig = new byte[8192];
System.Array.Copy(_p7s, 0, paddedSig, 0, _p7s.Length);

然后尝试将paddedSig放入PdfDictionary,如下所示:

PdfDictionary _pd = signatureUtil.GetSignatureDictionary("Signature1");
pd.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true));

pdfDocument.Close();

生成了一个名为“ results / injected.pdf”的新PDF,但是:

签名包含不正确,无法识别,损坏或可疑的数据。支持信息:SigDict /目录非法数据

我错过了什么?..如何将.p7s注入准备好的签名容器中?

回应Mkl的帖子:

我不明白的是如何将返回的PKCS#7字节嵌入到pdf中。假设byte [] _p7s是API_CALL的结果

byte[] _p7s = API_CALL;
byte[] paddedSig = new byte[8192];
System.Array.Copy(_p7s, 0, paddedSig, 0, _p7s.Length);

然后尝试将paddedSig放入PdfDictionary,如下所示:

PdfDictionary _pd = signatureUtil.GetSignatureDictionary("Signature1");
pd.Put(PdfName.Contents, new PdfString(paddedSig).SetHexWriting(true));

pdfDocument.Close();

结果是:

签名包含不正确,无法识别,损坏或可疑的数据。支持信息:SigDict /目录非法数据

尝试使用.p7s文件

我有一个example.p7s文件,我尝试使用下面提供的代码嵌入:

 byte[] _p7s = System.IO.File.ReadAllBytes("tmp/example.p7s");

 private static void Embed_P7S(Org.BouncyCastle.X509.X509Certificate[] _chain, byte[] _p7s)
    {
        PdfDocument document = new PdfDocument(new PdfReader("results/example-prepared.pdf"));
        Stream output = new FileStream("results/example-prepared-signed.pdf", FileMode.Create);

        ExternalInjectingSignatureContainer container2 = new ExternalInjectingSignatureContainer(_p7s);

        PdfSigner.SignDeferred(document, "Signature1", output, container2);
    }
}


internal class ExternalInjectingSignatureContainer :IExternalSignatureContainer
{
    public ExternalInjectingSignatureContainer(byte[] signature)
    {
        Signature = signature;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
    }

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

    public byte[] Signature;
}

结果:

example-prepared-signed.pdf未显示证书(与原始pdf相似),但尺寸大于原始pdf

original.pdf是105KB示例编写的是124KB示例编写符号的是121KB

这是.p7s

mkl

首先,您不必像您一样拆分签名过程。我已经看到了很多开发人员想要执行此操作的问题,但是严格来说,这是没有必要的(嗯,iText仍然会先创建一个准备好的PDF,然后再注入签名容器,但是可以保留它。在引擎盖下)。

仅当外部签名服务需要很长时间才能创建签名并且您不能将PDF保留在内存中时,才需要拆分过程。

我将在这里研究这两种变体。

单遍签名

如果您的外部签名服务以足够快的速度返回结果(完整的PKCS#7签名容器),则应使用此方法。基本代码与您的类似:

PdfSigner signer = new PdfSigner(new PdfReader("example.pdf"), new FileStream("example-signed.pdf", FileMode.Create), new StampingProperties().UseAppendMode());
signer.SetFieldName("Signature1");

PdfSignatureAppearance sigAppearance = signer.GetSignatureAppearance();
sigAppearance
    .SetPageRect(new Rectangle(144, 144, 200, 100))
    .SetPageNumber(1)
    .SetContact("This is contact")
    .SetReason("This is reason")
    .SetLocation("This is location")
    .SetSignatureCreator("This is signature creator");

ExternalServiceSignatureContainer container = new ExternalServiceSignatureContainer();

signer.SignExternalContainer(container, 8192);

您的代码的区别在于IExternalSignatureContainer实现:

public class ExternalServiceSignatureContainer : IExternalSignatureContainer
{
    public void ModifySigningDictionary(PdfDictionary signDic)
    {
        signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite);
        signDic.Put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
    }

    public byte[] Sign(Stream data)
    {
        // Call your external signing service to create a CMS signature container
        // for the data in the InputStream and return that signature container

        [... see below ...]
    }
}

根据您用于访问该外部签名服务的API的Sign不同,实现也有所不同。在每种情况下,我都假定API_CALL以字节数组的形式返回结果PKCS#7签名容器:

  • 您也许可以直接在信息流中调用它

    return YOUR_SIGNING_API_CALL_FOR_STREAM(data);
    
  • 或使用从流内容生成的byte []

    return YOUR_SIGNING_API_CALL_FOR_ARRAY(StreamUtil.InputStreamToArray(data));
    

    作为参数,

  • 否则您可能首先必须自己对数据进行哈希处理(例如,如下所示),然后将哈希发送给服务。

    byte[] hash = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256);
    return YOUR_SIGNING_API_CALL_FOR_HASH(hash)
    

signer已经的输出是已完成签名的PDF。

本质上就是这个答案已经讨论过的情况

两遍签名

如果您的外部签名服务没有足够快地返回结果(完整的PKCS#7签名容器)(例如,在使用批处理签名API的情况下,或者在服务等待较长时间确认的情况下),或者在您身边您可以在调用签名服务之前实现部件,然后在单独的程序中实现部件(确实有人这样做),则可以使用这种方法。

同样,基本代码与您的类似:

PdfSigner signer = new PdfSigner(new PdfReader("example.pdf"), new FileStream("example-prepared.pdf", FileMode.Create), new StampingProperties().UseAppendMode());
signer.SetFieldName("Signature1");

PdfSignatureAppearance sigAppearance = signer.GetSignatureAppearance();
sigAppearance
    .SetPageRect(new Rectangle(144, 144, 200, 100))
    .SetPageNumber(1)
    .SetContact("This is contact")
    .SetReason("This is reason")
    .SetLocation("This is location")
    .SetSignatureCreator("This is signature creator");

ExternalEmptySignatureContainer container = new ExternalEmptySignatureContainer();

signer.SignExternalContainer(container, 8192);

byte[] dataToSign = container.Data;

ExternalEmptySignatureContainer现在只提供了由签名服务后签署的数据,不注射签名容器还

public class ExternalEmptySignatureContainer : IExternalSignatureContainer
{
    public void ModifySigningDictionary(PdfDictionary signDic)
    {
        signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite);
        signDic.Put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
    }

    public byte[] Sign(Stream data)
    {
        // Store the data to sign and return an empty array

        [... see below ...]

        return new byte[0];
    }

    public byte[] Data;
}

根据您用于访问该外部签名服务的API的Sign不同,实现也有所不同。

  • 如果您的签名API需要原始数据进行签名,请使用从流内容生成的byte []

    Data = StreamUtil.InputStreamToArray(data);
    
  • 如果您的签名API期望原始数据的哈希值用于签名,请从流内容中像这样计算它

    Data = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256);
    

的输出signer是中介的,准备好的PDF。

下一步是调用签名服务并检索PKCS#7签名容器:

byte[] signature = YOUR_SIGNING_API_CALL(dataToSign);

最后,将签名容器注入准备好的PDF中:

PdfDocument document = new PdfDocument(new PdfReader("example-prepared.pdf"));
using (Stream output = new FileStream("example-prepared-signed.pdf", FileMode.Create))
{
    ExternalInjectingSignatureContainer container2 = new ExternalInjectingSignatureContainer(signature);

    PdfSigner.SignDeferred(document, "Signature1", output, container2);
}

IExternalSignatureContainer实现仅注入签名字节:

public class ExternalInjectingSignatureContainer : IExternalSignatureContainer
{
    public ExternalInjectingSignatureContainer(byte[] signature)
    {
        Signature = signature;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
    }

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

    public byte[] Signature;
}

输出是已定稿的,已签名的PDF。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

iText7:如何指定 PdfFont 使用的 OpenType 功能?

来自分类Dev

iText7 - 如何设置 LoggerFactory?

来自分类Dev

使用itext7的addind文本

来自分类Dev

使用 IText7 将 SVG 图像添加到 PDF

来自分类Dev

iText7 目录

来自分类Dev

如何使用itext7从标记的pdf中的结构元素中提取文本

来自分类Dev

我如何使用itext7从存储在Blob存储中的pdf中提取文本?

来自分类Dev

如何将字节数组转换为pdf?

来自分类Dev

如何使用带有 C# 的 itext7 将 u3d 添加到现有的 pdf 中

来自分类Dev

如何使用iTextsharp从pdf返回字节数组

来自分类Dev

将字节数组插入Blob列

来自分类Dev

将字节数组插入SQL Server

来自分类Dev

如何使用iText7在C#中从MemoryStream创建Image对象?

来自分类Dev

将字节数组转换为pdf

来自分类Dev

将字节数组转换为pdf

来自分类Dev

将字节数组转换为 UWP 的 pdf

来自分类Dev

iText7:如何获取段落的实际宽度

来自分类Dev

JDK1.7.0_79如何安装/配置iText7

来自分类Dev

如何在itext7中获取widthPoint

来自分类Dev

如何在wp7中将位图图像转换为字节数组?

来自分类Dev

如何使用 IText7 和 C# 在现有 PDF 中的内部链接下划线?

来自分类Dev

如何使用iText 7将PDF写入HttpResponseMessage

来自分类Dev

如何在 iText7/iText7.pdfhtml 的行首修复 CJK 标点符号

来自分类Dev

如何使用 angular 7 在 IE 11 中打印字节数组

来自分类Dev

Itext7 pdf.version.not.valid

来自分类Dev

从C#将字节数组插入SQL Server以及如何检索它

来自分类Dev

如何使用Dapper和sqlite插入语句保存字节数组

来自分类Dev

将字节数组写入ZipArchiveOutputStream

来自分类Dev

将PDF文件转换为字节数组的方式。(用于使用outputstream()进行刷新)

Related 相关文章

热门标签

归档