【问题标题】:iText or iTextSharp: when i use the ‘PdfStamper’ , target file use adobe.reader Verify signature failureiText or iTextSharp:当我使用‘PdfStamper’时,目标文件使用adobe.reader验证签名失败
【发布时间】:2018-05-03 09:54:44
【问题描述】:

我想删除最后一个签名,其他签名也可以使用 adobe.reader verify_sign 成功。

原文件已签名并使用adobe.reader验证签名成功,但是当我执行此代码时(我没有删除签名),目标文件使用adobe.reader验证签名失败。但是当我使用 adobe.reader 打开它们时,它们的内容显示正常。

我怀疑功能·PdfStamper· 破坏了签名数据。我应该如何避免这个问题?

我使用 itext 和 itextsharp(Java 和 C#),它们都是这个问题。 itex 和 itextsharp 版本是 5.5.10

我找到了url"AT least one signature is invalid" error message after removing signature from pdf using itext它已经删除了签名显示失败,但我没有删除签名,只有'new PdfStamper',目标文件使用adobe.reader验证签名失败。

谢谢~

PdfReader re = new PdfReader(filePath);
PdfStamper pdfStamper = new PdfStamper(re, new FileStream(temfilePath, FileMode.Create));
//TODO temfilePath verify signature failed.        
/*
 *    // not do this code
 *     //just remove the last signature.
 *     AcroFields acro = re.AcroFields;
 *     List<string> list = acro.GetSignatureNames();
 *     int i = 0;
 *     foreach (string s in list)
 *       {
 *           if (list.Count == i)
 *           {
 *               acro.ClearSignatureField(s); acro.RemoveField(s);
 *           }
 *           i++;
 *
 *       }
 */     
 pdfStamper.Close();
 re.Close();

【问题讨论】:

  • 您的方法存在两个主要问题:a 您在未使用自动损坏文件中所有签名的附加模式的情况下标记已签名的 pdf,以及 b b> 您尝试以不允许任何类型签名的方式在 pdf 更新中更改已签名 pdf 的表单字段结构。
  • 我不完全确定我是否正确理解了您的用例。是否要将pdf回滚到最外层之前签名的状态?然后布鲁诺的回答告诉你究竟该怎么做。或者您是否只想删除最外面的签名但保留自上一个签名以来的所有其他更改(例如表单填写)?那么你的任务就很重要了……
  • 或者您是否只想删除最外层的签名但保留自上一个签名以来的所有其他更改(例如表单填写)?这将是一个非常奇怪的要求。我想知道哪个用例需要这个。
  • @BrunoLowagie “这将是一个非常奇怪的要求。我想知道哪个用例需要这个。” - 那里有一些奇怪的东西。例如。很多人忘记带上各自的毛巾……
  • @BrunoLowagie 永远不要忘记你的毛巾! 光剑是个不错的玩具,但它能提供营养吗? ;)

标签: java c# itext


【解决方案1】:

签名被破坏是因为破坏了它们。请阅读official website 上的signatures documentation,您将找到Signatures 代码示例。

public void extractFirstRevision(
    String src, String dest, String sigName) throws IOException {
    PdfReader reader = new PdfReader(src);
    AcroFields af = reader.getAcroFields();
    FileOutputStream os = new FileOutputStream(dest);
    byte bb[] = new byte[1028];
    InputStream ip = af.extractRevision(sigName);
    int n = 0;
    while ((n = ip.read(bb)) > 0)
        os.write(bb, 0, n);
    os.close();
    ip.close();
}

这些是您需要的参数:

  • src: 签名源文件的路径
  • dest:你要创建的文件的路径
  • sigName:要提取修订的签名字段的名称

更新 1:

在评论中,您说要删除签名而不是(签名的?)内容,这就是我们通常所说的扁平化FlattenSignature 示例中对此进行了解释:

PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.setFormFlattening(true);
stamper.close();

现在您不会再看到任何签名面板,但会保留签名小部件。

更新 2:

在另一条评论中,您澄清您要删除一个字段,并且此操作会破坏 PDF 中的一个签名。昨天你发了问题The saved file is not the same size as the original file,我参考FAQ回答:Why do PDFs change when processing them?

由于我不知道的原因,您删除了该问题,但该常见问题解答中解释了您当前问题的根本原因之一。请允许我复制/粘贴该答案:

PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));

这将创建一个新的 PDF 文件,其中正在对对象进行重新排序。你 可以通过将此行更改为:

在追加模式下使用 PdfStamper
PdfStamper stamper = new PdfStamper(reader,
    new FileOutputStream(dest), '\0', true);

现在您正在创建 PDF 文件的增量更新。

您正在使用PdfStamper 重新组织PDF 中的对象。通过这样做,您破坏了签名(请参阅我的答案的第一行)。如果您不想破坏签名,则需要增量更新。增量更新不会对原始字节进行任何更改,从而使签名保持有效。

我没有对此进行测试,但理论上,您可以尝试在附加模式下删除第二个签名。这不会从文件中删除第二个签名(由于增量更新,它仍然存在),但是在 PDF 查看器中打开 PDF 的人将不再看到该签名,因为相关对象将在交叉引用表。

虽然这个“解决方案”在理论上可能有效,但这不太可能是您想要的解决方案。但是,您的用例非常不寻常,我怀疑是否有技术方法可以实现它。正如我在 cmets 中解释的那样,您的工作流程中的一个步骤应该已经导致第一个签名中断。

【讨论】:

  • 提取之前的签名修订不一定与删除最外层的签名相同。在未签名的修订之间可能存在其他更改,例如表格填写。即使在同一个最外层的增量更新中,除了签名之外也可能会发生变化。不过,据我了解,他只想删除签名。 (不过,我不得不承认,我不确定我是否正确理解了他......)
  • 我的pdf文件有两个签名,它们都可以验证签名。现在我用上面的代码(Bruno Lowagie 的代码)可以去掉最后一个签名。我了解“extractRevision”功能可以删除最后一个签名之前的内容。如果我只想删除最后一个签名而不删除内容,我该怎么办?这个想法能实现吗?谢谢
  • 您是说要扁平化签名吗?我会更新我的答案,但如果这不是你需要的,你必须澄清。
  • @xuelang0204 请分享一个示例文件,让您的要求有所不同,并勾勒出想要的结果。
  • 根据您如何执行第 3 步,由于数字签名的本质,第 3 步很有可能会破坏签名 A。如果您想保留签名 A,您犯的一个主要错误是:您没有在附加模式下使用 PdfStamper
猜你喜欢
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多