【问题标题】:Remove Byte Order Mark from signed PDF file?从签名的 PDF 文件中删除字节顺序标记?
【发布时间】:2014-12-04 12:00:48
【问题描述】:

我正在使用 iTextSharp 5.5.1 以使用分离签名(从第三方机构获得)对 PDF 文件进行数字签名。一切似乎都很好,文件是有效的,例如Adobe Reader 报告没有问题,将签名显示为有效等。

问题是 Java 客户端显然对这些文件有一些问题 - 该文件既无法打开也无法解析。
这些文件在标题中有一个字节顺序标记,这似乎导致了这种行为 (\x00EF\x00BB\x00BF)。

我可以像这样识别 BOM:

PdfReader reader = new PdfReader(path);
byte[] metadata = reader.Metadata;
// metadata[0], metadata[1], metadata[2] contain the BOM

如何删除 BOM(不丢失签名的有效性),或强制 iTextSharp 库不将这些字节附加到文件中?

【问题讨论】:

  • 我刚刚检查过,iTextSharp 并没有自己添加 BOM。要么是原始 PDF 在签名之前就有它们,要么你在某个时候添加了 BOM。
  • 元数据(嵌入在 PDF 文件中的某处)通常有一个 BOM,这没关系。 问题是 Java 客户端显然对这些文件有一些问题 - 哪些 Java 客户端?
  • @mkl:首先,InputStream 读取字节数组,然后 XMLPullParse (android) 在解析 xml 时抛出 XmlPullParserException。使用 BOMInputStream 从字符串中删除 BOM,因此 XMLPullParser 可以在任何情况下读取它。但我的要求是没有BOM的原始文件。
  • 我快速浏览了 iTextSharp 源代码,但找不到添加 BOM 的代码。要重现您的问题,您能否在 iTextSharp 应用程序签名前后共享 PDF?此外,您说您使用的是 iTextSharp 5.3.1; iTextSharp 存储库中没有该版本的标签,并且 SourceForge 上没有 5.3.1 发布文件夹。因此,看起来从未有过正式的 5.3.1 版本,或者由于某种原因已被撤销。您可能想要更新。
  • 好的,我正在查看文件。顺便说一句,您不仅要签名,还要加密文件。 不加密元数据不是最好的吗?这将允许支持 XMP 但不支持 PDF 的软件访问它们。有一个不加密元数据的加密选项。

标签: c# pdf itextsharp digital-signature byte-order-mark


【解决方案1】:

只是一个快速的方法:

首先:保存两个未加密的文件。 第二:在保存文件之前删除元数据 0 到 2

但是有一些注意事项:签名方法是否需要 BOM?加密方法是否需要 BOM?

在确定是否可以/应该删除 BOM 之前,您还必须确定在哪个阶段添加了 BOM。

我将快速搜索我的 pdf 结构文档,看看我能得到什么,但最简单的方法是(未尝试)将整个内容加载为字节数组,然后从开头删除 xEF xBB xBF文件,然后进行任何签名/加密。但是他们可能会再次添加它...

我会在周末发布更新:)

【讨论】:

    【解决方案2】:

    首先要做的事:一旦签署了 PDF,您就不应更改该 PDF 的任何字节,因为这样做会使签名无效。

    第二个观察:字节顺序标记不是 PDF 标题的一部分(PDF 总是以%PDF-1. 开头)。在这种情况下,它是XMP元数据处理指令中begin属性的值。我不知道任何 Java 客户端在文件中的任何位置都存在该字节序列的问题。如果他们确实有问题,那是客户端有问题,而不是文件有问题。

    Byte Order Mark 表示存在 UTF-8 字符。在 XMP 的上下文中,我们在 PDF 中有一个流,其中包含一个明文 XML 文件,该文件可以被非“PDF 感知”的软件使用。例如:

    2 0 obj
    <</Type/Metadata/Subtype/XML/Length 3492>>stream
    <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
    <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.0-jc003">
      <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
        <rdf:Description rdf:about=""
            xmlns:dc="http://purl.org/dc/elements/1.1/"
            xmlns:pdf="http://ns.adobe.com/pdf/1.3/"
            xmlns:xmp="http://ns.adobe.com/xap/1.0/"
          dc:format="application/pdf"
          pdf:Keywords="Metadata, iText, PDF"
          pdf:Producer="iText® 5.5.4-SNAPSHOT ©2000-2014 iText Group NV (AGPL-version); modified using iText® 5.5.4-SNAPSHOT ©2000-2014 iText Group NV (AGPL-version)"
          xmp:CreateDate="2014-11-07T16:36:55+01:00"
          xmp:CreatorTool="My program using iText"
          xmp:ModifyDate="2014-11-07T16:36:56+01:00"
          xmp:MetadataDate="2014-11-07T16:36:56+01:00">
          <dc:description>
            <rdf:Alt>
              <rdf:li xml:lang="x-default">This example shows how to add metadata</rdf:li>
            </rdf:Alt>
          </dc:description>
          <dc:creator>
            <rdf:Seq>
              <rdf:li>Bruno Lowagie</rdf:li>
            </rdf:Seq>
          </dc:creator>
          <dc:subject>
            <rdf:Bag>
              <rdf:li>Metadata</rdf:li>
              <rdf:li>iText</rdf:li>
              <rdf:li>PDF</rdf:li>
            </rdf:Bag>
          </dc:subject>
          <dc:title>
            <rdf:Alt>
              <rdf:li xml:lang="x-default">Hello World example</rdf:li>
            </rdf:Alt>
          </dc:title>
        </rdf:Description>
      </rdf:RDF>
    </x:xmpmeta>                                                            
    <?xpacket end="w"?>
    endstream
    

    此类不支持 PDF 的软件将查找序列 W5M0MpCehiHzreSzNTczkc9d,这是一个不太可能意外出现在数据流中的序列。

    begin 属性用于指示流中的字符使用 UTF-8 编码。它们在那里是因为它们在那里是一种很好的做法,但它们不是强制性的 (ISO-16684-1)。

    您可以按照自己的方式检索元数据 (byte[] metadata = reader.Metadata;),删除字节,然后使用 PdfStamper 实例更改流,如下所示:

     stamper.XmpMetadata = metadata;
    

    更改元数据后,您可以签署 PDF。

    请注意,您问题的一个方面让我感到惊讶。你写:

    // metadata[0], metadata[1], metadata[2] contain the BOM
    

    很奇怪,XMP 元数据的前三个字节包含 BOM。 XMP 元数据应该以&lt;?xpacket 开头。如果不是,那么您通过删除这些字节来做正确的事情。

    警告:PDF 可以包含不同级别的 XMP 元数据。现在,您正在研究最常见的一个:文档级元数据。您可能会遇到带有页面级 XMP 元数据的 PDF、在图像中带有 XMP 等...

    【讨论】:

    • 第二个观察:字节顺序标记不是头部的一部分。它是 begin 属性的值 - 它应该是这样的。但如果我没记错的话,OP 的示例签名和加密文件确实有一个 BOM,请参阅here。 (我实际上想调查一下,但忽略了这个问题。)
    • 我的意思是:它不是 PDF 标题的一部分。 PDF 标题如下所示:%PDF-1.。我会澄清的。
    • 我已经重读了这个问题。这是模棱两可的。它说 BOM 是 file 的标头的一部分,但该示例表明这不是真的:BOM 是在 XMP 元数据中找到的。 XMP 元数据封装在 PDF 文件的流中。
    • 是的,问题并不那么清楚,但确实,元数据流的内容(从签名和加密的示例文件中解密) ) 确实以 BOM 开头。而且我不确定该 BOM 是否无效或仅仅是不必要的。
    • lukasz 没有回答,即使他就相同的问题提出了一个新问题......即使我无法完全验证这个彻底的答案,我也会奖励赏金。
    猜你喜欢
    • 2010-09-22
    • 1970-01-01
    • 2015-01-01
    • 2015-08-18
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    • 2023-03-10
    • 2023-03-28
    相关资源
    最近更新 更多