iText 在 java 中验证 pdf 的完整性

iText verify integrity of a pdf in java

我的网络服务器生成一个 pdf 文件,对其进行签名,然后将其提供给客户。客户端对其进行多次签名(使用 Adob​​e Pro 使用不同的令牌),然后将其上传回服务器。

我想让服务器验证是否是之前服务器生成的pdf。我读到当应用多个签名时哈希值会改变。如何使用 iText 轻松进行此验证?

同一 PDF 中的多个集成签名通过 增量更新 应用,如果操作正确,请参见。 this answer 在信息安全堆栈交换上:

因此,虽然在某种程度上你读到的是真的

I read that the hash is changed when multiple signatures are applied.

(事实上,整个文件的散列值 会发生变化,除非发生极不可能的冲突),字节的散列值 您的初始签名适用于 保留并可以从文档中检索。

因此,根据您要检查的内容以及您仍然拥有的信息,有以下明显的选择:

比较初始版本

My web server generates a pdf, signs it, and give it to the client

如果您仍然将初始签名的 PDF 存储在某个地方(例如在数据库中)并且您想要检查客户端上传回您的 PDF 是否基于该 PDF,您需要做的就是检查是否客户端的 PDF 字节流以您存储的 PDF 的字节开始。

这不需要额外使用任何加密函数或特定于 PDF 的 API,只需比较字节或块。

检查签名

My web server generates a pdf, signs it, and give it to the client

如果您没有将初始签名的 PDF 存储在任何地方,或者您只想检查客户端上传回您的 PDF 是否基于您签名的许多可能的基础 PDF 之一,则无法进行直接修订比较或非常耗费资源。

在这种情况下你应该检查文档的初始签名是否

  • 有效且
  • 已由您的服务器创建。

检查签名有效性

有很多关于如何检查 PDF 中签名完整性的示例,例如

public PdfPKCS7 verifySignature(AcroFields fields, String name) throws GeneralSecurityException, IOException {
    System.out.println("Signature covers whole document: " + fields.signatureCoversWholeDocument(name));
    System.out.println("Document revision: " + fields.getRevision(name) + " of " + fields.getTotalRevisions());
    PdfPKCS7 pkcs7 = fields.verifySignature(name);
    System.out.println("Integrity check OK? " + pkcs7.verify());
    return pkcs7;
}

public void verifySignatures(String path) throws IOException, GeneralSecurityException {
    System.out.println(path);
    PdfReader reader = new PdfReader(path);
    AcroFields fields = reader.getAcroFields();
    ArrayList<String> names = fields.getSignatureNames();
    for (String name : names) {
        System.out.println("===== " + name + " =====");
        verifySignature(fields, name);
    }
    System.out.println();
}

C5_01_SignatureIntegrity.java 来自 iText 数字签名白皮书)

对于您的任务,您实际上可以简单地限制自己只检查第一个签名,但也检查其他签名可能也是一个好主意。

检查签名证书

要检查您的服务器是否已创建初始签名,我们假设您的 Web 服务器使用专用于此任务的 X509 证书(或一组已知的此类证书)对这些 PDF 进行签名。

您可以通过 PdfPKCS7 对象的 getSigningCertificate 方法检索用于创建初始签名的证书,您从第一个签名的 verifySignature 调用中检索到该对象。您所要做的就是检查证书是否是您专用于此任务的一个证书(或一组证书中的一个)。