我正在尝试执行以下设置来签名 pdf,分为客户端和服务器之间的异步步骤:
- 服务器接收 pdf 并计算其摘要。
- 服务器将摘要发送给客户端。
- 客户端稍后签署哈希值。
- 客户端将签名发送给服务器。
- 服务器将签名嵌入到 pdf 中。
我主要立足于PDF 签名摘要 https://stackoverflow.com/questions/29251895/pdf-signature-digest and 从文件摘要创建 pkcs7 签名 https://stackoverflow.com/questions/41767351/create-pkcs7-signature-from-file-digest
第二个问题允许我编写大部分代码,但是我发现文件的完整性已受到损害。我似乎无法序列化中间 pdf 以稍后嵌入签名(以确保没有时间戳被更改等)。但从第一个问题来看,这似乎是一个比我想象的更难的问题。真的可以做到吗?
我正在使用 pdfbox。
服务器代码:
PDDocument document = PDDocument.load(documentFile);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Example User");
signature.setLocation("Los Angeles, CA");
signature.setReason("Testing");
Calendar date = Calendar.getInstance();
signature.setSignDate(date);
document.addSignature(signature);
ExternalSigningSupport externalSigningSupport = document.saveIncrementalForExternalSigning(null);
byte[] content = IOUtils.toByteArray(externalSigningSupport.getContent());
MessageDigest md = MessageDigest.getInstance("SHA256", new BouncyCastleProvider());
byte[] digest = md.digest(content); // this is sent to client
我基本上所做的是将摘要发送给客户端进行签名,然后在服务器上重做上述步骤并设置客户端签名:
ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(fos);
externalSigning.setSignature(encodedSignature); // encodedSignature is received from client and computed based on the digest sent by the server
此设置最终导致文件的完整性被破坏,因为一旦我拥有了,我就会创建一个新的 PDSignatureencodedSignature
在服务器上嵌入它。有没有办法序列化调用 addSignature 后创建的 PDDocument,以便我稍后可以在服务器上反序列化它并添加客户端的签名?
我基本上所做的是将摘要发送给客户端进行签名,然后在服务器上重做上述步骤并设置客户端签名
如果你想要那些以上步骤要生成相同的文档,您需要
- 确保这些步骤的输入相同并且
- 提供相同的修订 ID 种子值。
如果这样做,则输出以上步骤与您的任务所需的相同。
确保输入相同
你的一步以上步骤很容易导致不同的输入:
Calendar date = Calendar.getInstance();
signature.setSignDate(date);
为了保证相同的输入,您必须确定date
仅一次,并且每次为同一签名交易执行这些步骤时都使用该单个值。
提供相同的修订 ID 种子值
根据规范的建议,PDFBox 尝试为每个 PDF 修订版提供唯一的 ID。不过,在当前的情况下,我们两次都需要相同的修订 ID以上步骤被处决。
幸运的是,PDFBox 允许我们提供它用来使修订 ID 足够唯一的种子值。
由于我们不希望在同一文档上始终使用相同的修订 ID,而只是在当前签名交易期间使用相同的修订 ID,因此我们应该仅在同一交易中使用相同的种子值。由于种子值很长,我们可以简单地使用对应于种子值的时间(以毫秒为单位)date
上面已经讨论过,即:
pdDocument.setDocumentId(date.getTimeInMillis());
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)