当前位置: 首页 > news >正文

通过数字证书对PDF电子文件进行数字签名/盖章

以下代码详细说明如何使用数字证书对PDF电子文件进行数字签名/盖章。PDF文件签署主要传递PDF文件,数字证书信息,签章图片3个信息。代码中需要的文件、数字证书、签章图片可访问开放签电子签章开源系统详细了解系统的实现与效果。也可通过gitee开源社区下载开放签开源电子签章系统,获取所有开源代码。

1、数字签名/盖章类SignService.java

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.*;
import com.resrun.service.pojo.CertificateProperty;
import com.resrun.service.pojo.RealPositionProperty;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Service;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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;/*** @Description: 签署业务* @Package: com.resrun.service.pdf* @ClassName: SignService* @copyright 北京资源律动科技有限公司 www.kaifangqian.com*/
@Service
public class SignService {public byte[] signingContract(byte[] pdfFile, byte[] signBadge, CertificateProperty cert,RealPositionProperty position) throws GeneralSecurityException, IOException, DocumentException {System.setProperty("javax.xml.parsers.DocumentBuilderFactory","com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");Security.addProvider(new BouncyCastleProvider());//1、解析证书// Java 安全属性文件中指定的默认 keystore 类型;如果不存在此类属性,则返回字符串 "jks"。 PKCS12KeyStore ks = KeyStore.getInstance(cert.getCertType());try {char[] chars = cert.getPassword().toCharArray();ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(cert.getCertFile());ks.load(byteArrayInputStream, chars);} catch (Exception e) {e.printStackTrace();}// 获取keystore中的所有别名String alias = (String) ks.aliases().nextElement();// 返回:请求的密钥, 入力参数:别名,用于恢复密钥的密码PrivateKey pk = (PrivateKey) ks.getKey(alias, cert.getPassword().toCharArray());// 证书链(按用户证书在前,根证书授权在后的顺序)Certificate[] chain = ks.getCertificateChain(alias);byte[] signedFileByte = null ;PdfReader reader = null ;ByteArrayOutputStream signedFile = null ;PdfStamper stamper = null ;try {//2、读取PDF文件reader = new PdfReader(pdfFile);signedFile = new ByteArrayOutputStream();stamper = PdfStamper.createSignature(reader, signedFile, '\0', null, true);//3、给签署属性服务PdfSignatureAppearance appearance = stamper.getSignatureAppearance();if (signBadge == null || position == null) {appearance.setCertificationLevel(certificationLevel);} else {int pageNum = 0;if (inspect) {//如果检查就会抛出检查异常pageNum = position.getPageNum();if (pageNum == 0)throw new IllegalArgumentException("Pdf page number must be greater than one....!!!");} else {pageNum = position.getPageNum() <= 0 ? 1 : position.getPageNum();}appearance.setVisibleSignature(new Rectangle(position.getStartx(), position.getStarty(), position.getEndx(), position.getEndy()), pageNum, null);// 添加签章图片Image img = Image.getInstance(signBadge);appearance.setSignatureGraphic(img);appearance.setImageScale(-1);appearance.setCertificationLevel(certificationLevel);appearance.setRenderingMode(renderingMode);}appearance.setReason(reason);appearance.setLocation(location);//4、调用签署  Creating the signatureExternalSignature pks = new PrivateKeySignature(pk, hashAlgorithm, BouncyCastleProvider.PROVIDER_NAME);ExternalDigest digest = new BouncyCastleDigest();MakeSignature.signDetached(appearance, digest, pks, chain, null, ocspClient, tsaClient, 0, cryptoStandard);signedFileByte = signedFile.toByteArray();} catch (Exception e){e.printStackTrace();}finally {// 关闭流if (stamper != null) stamper.close();if (signedFile != null) signedFile.close();if (reader != null) reader.close();}return signedFileByte ;}//是否判断校验不校验PDF页码private boolean inspect = true;private int certificationLevel = PdfSignatureAppearance.NOT_CERTIFIED;private PdfSignatureAppearance.RenderingMode renderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC;private String hashAlgorithm = DigestAlgorithms.SHA256;private MakeSignature.CryptoStandard cryptoStandard = MakeSignature.CryptoStandard.CMS;private String reason = "防伪造防篡改数字校验"; //原因private String location; //位置private TSAClient tsaClient; //时间戳服务private OcspClient ocspClient;public boolean isInspect() {return inspect;}public void setInspect(boolean inspect) {this.inspect = inspect;}public int getCertificationLevel() {return certificationLevel;}public void setCertificationLevel(int certificationLevel) {this.certificationLevel = certificationLevel;}public PdfSignatureAppearance.RenderingMode getRenderingMode() {return renderingMode;}public void setRenderingMode(PdfSignatureAppearance.RenderingMode renderingMode) {this.renderingMode = renderingMode;}public String getHashAlgorithm() {return hashAlgorithm;}public void setHashAlgorithm(String hashAlgorithm) {this.hashAlgorithm = hashAlgorithm;}public MakeSignature.CryptoStandard getCryptoStandard() {return cryptoStandard;}public void setCryptoStandard(MakeSignature.CryptoStandard cryptoStandard) {this.cryptoStandard = cryptoStandard;}public String getReason() {return reason;}public void setReason(String reason) {this.reason = reason;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public TSAClient getTsaClient() {return tsaClient;}public void setTsaClient(TSAClient tsaClient) {this.tsaClient = tsaClient;}public OcspClient getOcspClient() {return ocspClient;}public void setOcspClient(OcspClient ocspClient) {this.ocspClient = ocspClient;}}

2、证书文件属性类,主要存储证书信息CertificateProperty.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** @Description: 证书文件属性类* @Package: com.resrun.service.pojo* @ClassName: CertificateProperty* @copyright 北京资源律动科技有限公司*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CertificateProperty implements Serializable {private static final long serialVersionUID = -2073805779543816269L;private  byte[] certFile;/** 证书的类型 比如:PKCS12和jks*/private  String certType;/** 证书密码 */private  String password;}

3、签署位置信息类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;/*** @Description: 经过计算后的文件签署位置属性类* @Package: com.resrun.service.pojo* @ClassName: PositionProperty* @copyright 北京资源律动科技有限公司*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class RealPositionProperty implements Serializable {private static final long serialVersionUID = 8586984409612483553L;/** 签章左下角x坐标 */private  float startx;/** 签章左下角y坐标*/private  float starty;/** 签章右上角x坐标*/private  float endx;/** 签章右上角x坐标*/private  float endy;private  int pageNum;// 填写值,填写专用private String value ;//对齐方式private String align ;//字体private String fontFamily ;//文字大小private Integer fontSize ;
}

相关文章:

  • 【JavaWeb学习-第四章(1)】Ajax
  • QT编译并部署QtMqtt相关环境+跑测demo【超详细教程】
  • 【大语言模型】Transformer原理以及运行机制
  • 面向对象设计与分析40讲(17)双重检查锁定(double-checked locking)范式
  • PostgreSQL 作为向量数据库:入门和扩展
  • redhat 8 安装openstack
  • Elasticsearch之常用DSL语句
  • 数字人私人定制
  • Python将普通图像转化为栅格影像
  • python3遇到Can‘t connect to HTTPS URL because the SSL module is not available.
  • m3u8网络视频文件下载方法
  • HDMI2.1输入转4Port MIPI/LVDS输出,嵌入式SPI闪存固件存储,VR和AR应用首选国产芯片方案-LT6911GXC
  • 设计模式——行为型模式
  • 成为一名FPGA工程师:面试题与经验分享
  • 智慧园区物联综合管理平台感知对象管理能力简述
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • 【node学习】协程
  • 2017-08-04 前端日报
  • Gradle 5.0 正式版发布
  • tweak 支持第三方库
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 读懂package.json -- 依赖管理
  • 飞驰在Mesos的涡轮引擎上
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 漂亮刷新控件-iOS
  • 前端面试之闭包
  • 使用Swoole加速Laravel(正式环境中)
  • 项目管理碎碎念系列之一:干系人管理
  • 学习HTTP相关知识笔记
  • 学习笔记TF060:图像语音结合,看图说话
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 正则表达式小结
  • 说说我为什么看好Spring Cloud Alibaba
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (145)光线追踪距离场柔和阴影
  • (C语言)fgets与fputs函数详解
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (转)Google的Objective-C编码规范
  • (转)Linux下编译安装log4cxx
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .htaccess配置重写url引擎
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .NET Core 成都线下面基会拉开序幕
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
  • .NET简谈设计模式之(单件模式)
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • /bin/rm: 参数列表过长"的解决办法
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思