如何计算PDF文档摘要且不更新修改日期?
解决PDF分步签名时摘要不一致的问题
问题根源
你的代码里有两个操作导致每次生成的PDF字节内容不一致:
- 多余的
PdfDocument和PdfAcroForm修改:调用acroForm.setSignatureFlags(PdfAcroForm.SIGNATURE_EXIST)会直接修改文档内容,造成字节变化。 PdfSigner默认会更新文档的ModDate字段,加上你设置的signDate,每次生成的中间文档元数据都不一样,最终导致摘要计算结果不同。
解决方案
- 删除不必要的文档修改操作:不需要提前初始化
PdfDocument和修改表单签名标志,PdfSigner在处理签名时会自动处理相关逻辑。 - 配置
StampingProperties保留原文档的修改日期,阻止ModDate被更新。 - 修正代码中的变量引用错误(
digestHash未定义,应使用calcDigest.pdfDigest)。
修改后的代码
public class MyDigestCalculator extends ExternalBlankSignatureContainer { public byte[] pdfDigest; public MyDigestCalculator(PdfName filter, PdfName subFilter) { super(filter, subFilter); } @Override public byte[] sign(InputStream is) throws GeneralSecurityException { try { final byte[] bytes = is.readAllBytes(); pdfDigest = DigestAlgorithms.digest(new ByteArrayInputStream(bytes), "SHA-256"); return new byte[0]; } catch (IOException e) { throw new GeneralSecurityException("Can't get digest from file hash", e); } } } public class DocumentSigner { public String calculatePdfDigest(byte[] pdfBytes, SignatureProperties signature, boolean lockFields, Calendar signDate) throws IOException, GeneralSecurityException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PdfReader reader = new PdfReader(new ByteArrayInputStream(pdfBytes)); // 配置保留原修改日期,使用追加模式 StampingProperties stampingProps = new StampingProperties() .useAppendMode() .preserveModificationDate(); PdfSigner signer = new PdfSigner(reader, baos, stampingProps); // 若不需要强制设置签名日期可注释此行;若必须设置,确保每次传入完全相同的日期 // signer.setSignDate(signDate); MyDigestCalculator calcDigest = new MyDigestCalculator(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached); signer.signExternalContainer(calcDigest, 8120); // 修正变量引用错误 String digest = (calcDigest.pdfDigest != null ? new BigInteger(1, calcDigest.pdfDigest).toString(16) : null); return digest; } }
关键说明
StampingProperties.preserveModificationDate():这是核心配置,让iText处理文档时不更新原有的ModDate字段,确保每次生成的中间文档元数据一致。- 移除多余的文档操作:那些额外的
PdfDocument和表单修改会改变文档字节,破坏摘要计算的一致性。 - 关于
signDate:如果业务不需要强制设置签名日期,建议注释掉相关代码;若必须设置,要保证每次调用时传入完全相同的日期对象,避免因日期细微差异导致元数据变化。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

