You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算PDF文档摘要且不更新修改日期?

解决PDF分步签名时摘要不一致的问题

问题根源

你的代码里有两个操作导致每次生成的PDF字节内容不一致:

  • 多余的PdfDocument和PdfAcroForm修改:调用acroForm.setSignatureFlags(PdfAcroForm.SIGNATURE_EXIST)会直接修改文档内容,造成字节变化。
  • PdfSigner默认会更新文档的ModDate字段,加上你设置的signDate,每次生成的中间文档元数据都不一样,最终导致摘要计算结果不同。

解决方案

  1. 删除不必要的文档修改操作:不需要提前初始化PdfDocument和修改表单签名标志,PdfSigner在处理签名时会自动处理相关逻辑。
  2. 配置StampingProperties保留原文档的修改日期,阻止ModDate被更新。
  3. 修正代码中的变量引用错误(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:13:23