关于这个:
"这是因为我不仅要验证签名的 PDF 是
真实的,而且它与我记录在案的未签名 PDF 相同”
假设您只想知道您在服务器上获取的文档是真实的:
创建签名文档时,您可以选择仅签名文件的一部分或整个文档。然后,您可以使用“整个文档”签名,如果您返回到服务器上的文档是“真实的”(这意味着签名验证成功),那么它肯定是您记录在案的同一文档。
值得一提的是,PDF签名有两种类型,批准签名和认证签名。来自文档Digital Signatures in PDF from Adobe:
(...) 批准签名,其中有人签署文件以显示
同意、批准或接受。经认证的文件是具有
发起人在文件时应用的证明签名
可以使用了。发起者指定允许哪些更改;
选择允许的三个修改级别之一:
假设您想将服务器上的某个已签名文档与数据库上的未签名文档进行匹配:
对于证件识别,我建议单独处理。一旦可以打开一个文档,就可以从其所有页面的解压缩内容的串联中创建一个哈希(例如 md5),然后将其与来自原始文档的另一个类似的哈希进行比较,(可以生成一次并存储在数据库中)。
我这样做的原因是它将独立于文档上使用的签名类型。即使在 PDF 文件中编辑表单域、添加注释或创建新签名,页面内容也不会被修改,它始终保持不变。
如果你使用的是iText,你可以通过PdfReader.getPageContent方法获取页面内容的字节数组,并将结果用于computing a MD5 hash。
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 条目指示。这
range 通常是整个文件,包括签名字典
但不包括签名值本身(内容条目)。
-对象摘要 (PDF 1.5) 通过有选择地在内存中遍历对象的子树来计算,从引用的对象开始,
这通常是根对象。生成的摘要以及
有关如何计算的信息,被放置在签名中
参考字典 (...)。