使用文档哈希将签名的PDF与未签名的PDF进行比较

经过广泛的谷歌搜索,我开始怀疑我是否在某种程度上错过了数字签名的重点。

这基本上是我认为我原则上应该能做到的,我希望iTextSharp能够允许我:

我正在用C#和.NET编写,并使用iTextSharp来解析PDF文件。 我有一个未签名的PDF文件,也​​是同一文件的签名版本。

我知道数字签名从根本上散列了PDF数据,用私钥对其进行加密,然后部分validation过程是使用公钥对其进行解密,并确保在再次进行散列时结果与PDF数据匹配。

除此之外,我想获得这个解密的文档哈希,并将其与我的未签名PDF生成的文档哈希进行比较。 这是因为我不仅要validation签名的PDF是否真实,而且还要记录我记录的相同的无签名PDF。 我想我也可以通过比较PDF数据(没有签名)和记录的PDF数据来做到这一点。

我目前还没有弄清楚如何做到这一点! 即:

  1. 如何从签名的PDF中提取PDF数据,不包括签名?
  2. 或者,如何从未签名的PDF生成哈希?
  3. 与2.一起,如何从PDF签名中提取解密的哈希?

希望这很清楚,我没有错过任何地方的观点!

对这个:

“这是因为我不仅想validation签名的PDF是否真实,而且还记录了我记录的相同的无签名PDF”

假设您只是想知道您在服务器上获得的文档是真实的:

创建签名文档时,您可以选择仅签署文件的一部分或整个文档。 然后,您可以使用“整个文档”签名,如果您在服务器上获得的文档是“真实的”(这意味着签名的validation成功),那么它肯定是您记录的同一文档。

值得一提的是,有两种类型的PDF签名,批准签名和认证签名。 来自Adobe的PDF文档数字签名 :

(…)批准签名,如果有人签署文件以表示同意,批准或接受。 经认证的文件是在文件准备好使用时具有发起人应用的certificate签名的文件。 发起人指定允许的更改; 选择允许的三个修改级别之一:

  • 没有变化
  • 仅填写表格
  • 表格填写和评论

假设您要匹配服务器上的某些已签名文档,并在数据库中使用其未签名的等效文档:

对于文件识别,我建议单独处理。 一旦打开文档,就可以从其所有页面的解压缩内容的串联中创建散列(例如md5),然后将其与原始文档中的另一个类似散列进行比较(可以生成一次并存储)在数据库中)。

我这样做的原因是它将独立于文档上使用的签名类型。 即使在PDF文件中编辑表单字段,或添加注释,或创建新签名,页面内容也永远不会被修改,它将始终保持不变。

如果您使用的是iText,则可以使用PdfReader.getPageContent方法获取页面内容的字节数组,并使用结果计算MD5哈希值 。

Java中的代码可能如下所示:

PdfReader reader = new PdfReader("myfile.pdf"); MessageDigest messageDigest = MessageDigest.getInstance("MD5"); int pageCount = reader.getNumberOfPages(); for(int i=1;i <= pageCount; i++) { byte[] buf = reader.getPageContent(i); messageDigest.update(buf, 0, buf.length); } byte[] hash = messageDigest.digest(); 

此外,如果服务器收到一个未签名的文件,则返回签名,签名可能只涉及文件的一部分而不是全部。 在这种情况下,签名摘要可能不足以识别文件。

从PDF规范(我帐户中的粗体部分):

通过计算文档中数据(或部分数据)的摘要,并将摘要存储在文档中来创建签名。(...)有两种定义的技术用于计算所有或者内容的可再现摘要。 PDF文件的一部分:

- 在文件中的字节范围内计算字节范围摘要 ,由签名字典中的ByteRange条目指示。 此范围通常是整个文件,包括签名字典,但不包括签名值本身(Contents条目)。

- 对象摘要(PDF 1.5)是通过选择性地遍历内存中的对象子树来计算的,从引用的对象开始,通常是根对象。 生成的摘要以及有关如何计算的信息放在签名参考字典(...)中。

validation签名PDF完整性的策略:

  1. 不要首先发送未签名的PDF。 使用iText(适用于Linux的应用程序的Java版本),使用CERTIFIED_FORM_FILLING对文档进行签名和CERTIFIED_FORM_FILLING

  2. 让最终用户将其签名添加到表单字段并将其发回。 这可以做到,因为对表单的更改不会破坏文档认证。

  3. validation签名和文档证书。

您应该能够从iText文档中找出如何完成所有这些工作: http : //itextpdf.sourceforge.net/howtosign.html

您需要做的就是validation认证文档与原始文档是否相同,将文档元数据与原始元数据进行比较。 作为潜在的好候选人,脑海中浮现出这个头衔。

要从pdf获取标题以使用iText进行比较,您只需使用以下代码:

 PdfReader reader = new PdfReader("AsignedPDF.pdf"); string s = reader.Info["Title"];