因为公司对发出的pdf报告进行有权威的认证,所以需要使用数字签名。
Apache PDFBox: 实现不了,
spire.pdf.free: 虽然可以用,但是免费的他有限制,限制了转为数字签名的pdf只有10页
iText5:所以使用了iText5
首先你要有CA证书、密码、以及时间戳服务器(TSA)的url、用户、密码。
接下来引入对应的jar
<!-- iText core library -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.4</version>
</dependency>
<!-- Bouncy Castle Core Library -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
然后就是代码了
package com.stc;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.TSAClientBouncyCastle;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Enumeration;
/**
* @ClassName: SignPdfWithTimestamp
* @Description: TODO
* @Author: ZhangZeYu
* @date: 2024/7/3 14:39
* @Version: V1.0
*/
public class SignPdfWithTimestamp {
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
// 添加BouncyCastleProvider
Security.insertProviderAt(new BouncyCastleProvider(), 1);
// PDF文件路径
String src = "E:/pdfszzs.pdf";
// 签名后PDF文件路径
String dest = "E:/pdfszzs22.pdf";
// PKCS#12文件路径
String pkcs12 = "E:/1111.pfx";
// PKCS#12文件密码
String password = "1111";
// TSA服务器URL
String tsaUrl = "http://your-tsa-server.com/ts";
// 加载证书和私钥
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new java.io.FileInputStream(pkcs12), password.toCharArray());
Enumeration<String> aliases = ks.aliases();
String alias = aliases.nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, password.toCharArray());
Certificate[] chain = ks.getCertificateChain(alias);
// 创建PDF阅读器和签署者
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason("Signed by example");
appearance.setLocation("Somewhere");
// 设置签名外观的其他属性,如签名位置等
// 创建签名和摘要实例
ExternalSignature pks = new PrivateKeySignature(pk, "SHA-256", "BC");
ExternalDigest digest = new BouncyCastleDigest();
// 创建时间戳客户端
TSAClientBouncyCastle tsaClient = new TSAClientBouncyCastle(tsaUrl);
// 执行签名并应用时间戳
MakeSignature.signDetached(appearance, digest, pks, chain, null, null, tsaClient, 0, MakeSignature.CryptoStandard.CMS);
// 关闭资源
stamper.close();
os.close();
}
}