【问题标题】:How to extract attachment from digitally signed pdf?如何从数字签名的pdf中提取附件?
【发布时间】:2013-10-02 08:15:50
【问题描述】:

我有一些 C# 代码可以从 pdf 文件中提取所有附件。它工作得很好,即使它是附加文档级别或作为文件注释。

但是,如果我对这些 pdf 文件进行数字签名(和时间戳),附件的类型会从注释(或文件附件)更改为“小部件”或其他内容。我不是 pdf 专家,如果 pdf 已签名,我找不到任何方法来提取附件。

任何帮助表示赞赏!

[编辑]

无签名示例:samplepdf_notsigned.pdf

带签名的示例(使用 SetaPDF-Signer API 签名):samplepdf_signed.pdf

代码块如下:

/*
 * annotations
 */
iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader("samplepdf_annotations.pdf");
for (int i = 1; i <= reader.NumberOfPages; i++)
{
    iTextSharp.text.pdf.PdfArray array = reader.GetPageN(i).GetAsArray(iTextSharp.text.pdf.PdfName.ANNOTS);
    if (array == null) continue;
    for (int j = 0; j < array.Size; j++)
    {
        iTextSharp.text.pdf.PdfDictionary annot = array.GetAsDict(j);
        if (iTextSharp.text.pdf.PdfName.FILEATTACHMENT.Equals(annot.GetAsName(iTextSharp.text.pdf.PdfName.SUBTYPE)))
        {
            iTextSharp.text.pdf.PdfDictionary fs = annot.GetAsDict(iTextSharp.text.pdf.PdfName.FS);
            iTextSharp.text.pdf.PdfDictionary refs = fs.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
            foreach (iTextSharp.text.pdf.PdfName name in refs.Keys)
            {
                // I CAN GET THE ATTACHMENT HERE
                string filename = fs.GetAsString(name).ToString();
                byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes((iTextSharp.text.pdf.PRStream)refs.GetAsStream(name));
            }
        }
        else
        {
            iTextSharp.text.pdf.PdfDictionary fs = annot.GetAsDict(iTextSharp.text.pdf.PdfName.FS);
            iTextSharp.text.pdf.PdfDictionary refs = fs.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
            foreach (iTextSharp.text.pdf.PdfName name in refs.Keys)
            {
                // I CAN GET THE ATTACHMENT HERE
                string filename = fs.GetAsString(name).ToString();
                byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes((iTextSharp.text.pdf.PRStream)refs.GetAsStream(name));
            }
        }
    }
} 

/*
 * embedded level
 */
iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader("samplepdf_embedded.pdf");
iTextSharp.text.pdf.PdfDictionary root = reader.Catalog;
iTextSharp.text.pdf.PdfDictionary documentnames = root.GetAsDict(iTextSharp.text.pdf.PdfName.NAMES);
iTextSharp.text.pdf.PdfDictionary embeddedfiles = documentnames.GetAsDict(iTextSharp.text.pdf.PdfName.EMBEDDEDFILES);
iTextSharp.text.pdf.PdfArray filespecs = embeddedfiles.GetAsArray(iTextSharp.text.pdf.PdfName.NAMES);
for (int i = 0; i < filespecs.Size; ) {
    filespecs.GetAsString(i++);
    iTextSharp.text.pdf.PdfDictionary filespec = filespecs.GetAsDict(i++);
    iTextSharp.text.pdf.PdfDictionary refs = filespec.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
    foreach (iTextSharp.text.pdf.PdfName key in refs.Keys)
    {
        iTextSharp.text.pdf.PRStream stream = (iTextSharp.text.pdf.PRStream)iTextSharp.text.pdf.PdfReader.GetPdfObject(refs.GetAsIndirectObject(key));
        // I CAN GET THE ATTACHMENT HERE
        string filename = filespec.GetAsString(key).ToString();
        byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes(stream);
    }
}

【问题讨论】:

  • 您应该提供更多信息。例如。您当前的代码如何提取附件?您如何对 PDF 进行签名和时间戳记?此外,样本文件(未签名和已签名)可能会有所帮助。
  • 编辑后,我添加了我的代码和一些示例 pdf 文件。谢谢!
  • 到底发生了什么?我假设一个空访问?

标签: c# .net pdf digital-signature


【解决方案1】:

我认为问题出在您尝试查找文件附件注释的顶部代码块中。在其内部循环(检查每个注释)中,您有一个构造:

if (iTextSharp.text.pdf.PdfName.FILEATTACHMENT.Equals(annot.GetAsName(iTextSharp.text.pdf.PdfName.SUBTYPE)))
{
    [...block 1...]
}
else
{
    [...block 2...]
}

这里的第 1 块和第 2 块是相同的,即您在任何情况下都在那里执行代码,对于 文件附件的注释和 不是 的注释。

只要您的 PDF 中唯一的注释是文件附件,那没关系,但只要有另一个注释,该块 2 中的代码

iTextSharp.text.pdf.PdfDictionary fs = annot.GetAsDict(iTextSharp.text.pdf.PdfName.FS);
iTextSharp.text.pdf.PdfDictionary refs = fs.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
foreach (iTextSharp.text.pdf.PdfName name in refs.Keys)
{
    // I CAN GET THE ATTACHMENT HERE
    string filename = fs.GetAsString(name).ToString();
    byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes((iTextSharp.text.pdf.PRStream)refs.GetAsStream(name));
}

很可能会在您的脸上炸开,因为大多数其他注释类型没有 /EF 条目,因此refsnullrefs.Keys 会引发异常。

不幸的是,集成的 PDF 签名是可以作为注释附加到某些页面的表单字段(即使不可见)。因此,签署 PDF 会引发第 2 块中的陷阱。

问题出现了,您为什么要尝试在 Block 2 中提取附件。根据 PDF 规范,文件附件注释必须包含 if 查找的类型信息。因此,任何符合规范的 PDF 都不会让您的代码进入文件附件注释的第 2 块。因此,您可以简单地删除该块 2。

【讨论】:

  • 你是对的,块 2 是错误的(与块 1 相同)。知道如何在 PDF 签名时获取附件吗?我可以直接联系他们还是应该先删除签名(清除表单字段)?如果是这样,我怎么能用 iTextSharp 做到这一点?
  • 您为什么尝试从不是文件附件注释的注释中检索文件附件?块 2 应该什么都不做。如果您认为可能存在错误标记的注释,则必须检查您尝试检索的每个对象是否有 null
猜你喜欢
  • 2011-09-12
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 2012-07-24
  • 2015-04-05
相关资源
最近更新 更多