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

如何用iText 8.0.3 Java库对PDF哈希进行PAdES合规签名?

使用iText 8.0.3实现PDF哈希签名及PAdES合规配置

核心思路

要实现“仅对PDF文档哈希签名、返回签名结果”并满足PAdES合规要求,需基于PdfPadesSigner的扩展能力,通过自定义外部签名逻辑分离文档哈希计算与签名生成步骤,同时配置对应签名属性与合规等级。

步骤1:自定义外部签名实现

实现IExternalSignature接口,在sign方法中获取待签字节数组(对应PDF文档的签名摘要),执行哈希签名逻辑(示例用BouncyCastle模拟,实际可替换为HSM、密钥库等签名服务),返回签名结果。

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.itextpdf.signatures.IExternalSignature;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;

public class CustomHashSigner implements IExternalSignature {
    private final PrivateKey privateKey;
    private final String hashAlgorithm;
    private final String encryptionAlgorithm;

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public CustomHashSigner(PrivateKey privateKey, String hashAlgorithm, String encryptionAlgorithm) {
        this.privateKey = privateKey;
        this.hashAlgorithm = hashAlgorithm;
        this.encryptionAlgorithm = encryptionAlgorithm;
    }

    @Override
    public byte[] sign(byte[] message) throws Exception {
        // message为iText预处理后的待签字节数组,对应PDF文档的签名摘要
        // 执行哈希签名逻辑,返回签名结果
        Signature signature = Signature.getInstance(String.format("%swith%s", hashAlgorithm, encryptionAlgorithm), "BC");
        signature.initSign(privateKey);
        signature.update(message);
        return signature.sign();
    }

    @Override
    public String getHashAlgorithm() {
        return hashAlgorithm;
    }

    @Override
    public String getEncryptionAlgorithm() {
        return encryptionAlgorithm;
    }
}

步骤2:配置PdfPadesSigner与签名属性

初始化PdfPadesSigner,设置PAdES合规等级,添加commitment-type-indication、signer-location等属性,配置时间戳服务(针对B-T/B-LT/B-LTA等级)。

import org.itextpdf.kernel.pdf.PdfReader;
import org.itextpdf.kernel.pdf.PdfWriter;
import org.itextpdf.signatures.PdfPadesSigner;
import org.itextpdf.signatures.SignatureLevel;
import org.itextpdf.signatures.SignerProperties;
import org.itextpdf.signatures.TSAClientBouncyCastle;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;

public class PadesHashSignatureDemo {
    public static void main(String[] args) throws Exception {
        // 1. 加载密钥库与私钥证书
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream("your-keystore.p12"), "password".toCharArray());
        String alias = ks.aliases().nextElement();
        PrivateKey privateKey = (PrivateKey) ks.getKey(alias, "password".toCharArray());
        Certificate[] chain = ks.getCertificateChain(alias);

        // 2. 初始化PdfPadesSigner
        PdfReader reader = new PdfReader("input.pdf");
        PdfWriter writer = new PdfWriter(new FileOutputStream("output.pdf"));
        PdfPadesSigner signer = new PdfPadesSigner(reader, writer, null);

        // 3. 配置签名属性
        SignerProperties signerProperties = new SignerProperties();
        // 设置签名位置
        signerProperties.setLocation("Shanghai, CN");
        // 添加承诺类型(示例为"批准"类型)
        signerProperties.addCommitmentType(SignerProperties.CommitmentTypeProperty.PROOF_OF_APPROVAL);
        // 添加内容提示
        signerProperties.addContentHint("Signed PDF Document", "UTF-8");
        // 设置MIME类型(默认application/pdf,可显式指定)
        signerProperties.setMimeType("application/pdf");
        // 配置签名外观(可选,按需设置)
        signerProperties.setPageNumber(1)
                       .setSignatureRectangle(new float[]{36, 748, 144, 780})
                       .setSignatureName("Signature");

        // 4. 设置PAdES合规等级
        // 可选值:PADES_B_B, PADES_B_T, PADES_B_LT, PADES_B_LTA
        signer.setSignatureLevel(SignatureLevel.PADES_B_LTA);

        // 5. 配置时间戳服务(针对B-T/B-LT/B-LTA等级)
        TSAClientBouncyCastle tsaClient = new TSAClientBouncyCastle(
                "http://your-tsa-server-url",
                null,
                null,
                4096,
                "SHA-256"
        );
        signer.setTsaClient(tsaClient);

        // 6. 绑定自定义签名实现并执行签名
        CustomHashSigner customSigner = new CustomHashSigner(privateKey, "SHA-256", "RSA");
        signer.signExternal(customSigner, chain);

        // 若需单独获取文档哈希的签名结果,可在CustomHashSigner的sign方法中存储或返回
    }
}

关键配置说明

  • PAdES等级适配:
    • B-B:基础签名,无需时间戳,仅需签名本身
    • B-T:添加签名时间戳,需配置tsaClient
    • B-LT:长期验证,依赖时间戳确保签名长期有效
    • B-LTA:归档长期验证,需额外归档时间戳(iText自动处理,只需配置有效TSA)
  • 签名属性添加:
    • commitment-type-indication:通过addCommitmentType指定,支持PROOF_OF_APPROVAL、PROOF_OF_CREATION等预定义类型
    • content-hints:通过addContentHint添加描述与编码格式
    • signer-location:通过setLocation设置签名者地理位置
    • content-time-stamp:依赖TSA服务配置,自动添加到签名属性中

注意事项

  • 实际场景中,CustomHashSigner的sign方法需替换为真实签名逻辑(如调用硬件加密机API)
  • 确保依赖包完整:iText 8.0.3核心包、BouncyCastle相关包(bcprov-jdk15on、bcpkix-jdk15on)
  • 时间戳服务需支持RFC 3161标准

内容的提问来源于stack exchange,提问作者Xavi Martí Lull

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 01:45:04