通过数字证书对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"。 PKCS12
KeyStore 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 signature
ExternalSignature 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 ;
}
通过数字证书对PDF电子文件进行数字签名/盖章的更多相关文章
- makecert 制作数字证书 给DLL加一个数字签名
声明:文章整理自互联网 我仅需要给dll添加(替换)一个签名,所以我只看了第一步和第三步,其余的部分我没有测试,不能保证内容的是否正确. 看了很多关于DLL加签名的教程 大多是错误的 完全无法正常走下 ...
- C#使用BouncyCastle生成PKCS#12数字证书
背景 生成数字证书用于PDF文档数字签名 数字证书需要考虑环境兼容性,如linux.windows 网上资料不全或版本多样 本文章主要介绍了在C#中使用BouncyCastle生成PKCS#12个人信 ...
- HTTPS 基础知识(密钥、对称加密、非对称加密、数字签名、数字证书)
HTTPS 概述 对称加密 非对称加密 非对称加密改良方案 非对称加密 + 对称加密 中间人攻击 数字证书 数字签名 HTTPS 工作原理 HTTPS 概述 HTTPS(全称:Hyper Text T ...
- 通俗理解数字签名,数字证书和https
最近在开发关于PDF合同文档电子签章的功能,大概意思就是在一份PDF合同上签名,盖章,使其具有法律效应.签章有法律效应必须满足两个条件: 能够证明签名,盖章者是谁,无法抵赖 PDF合同在签章后不能被更 ...
- 转!!通俗理解数字加密,数字签名,数字证书和https
原博文地址:https://www.jianshu.com/p/4932cb1499bf 前言 最近在开发关于PDF合同文档电子签章的功能,大概意思就是在一份PDF合同上签名,盖章,使其具有法律效应. ...
- 通俗理解数字签名,ssl数字证书和https
前言 最近在开发关于PDF合同文档电子签章的功能,大概意思就是在一份PDF合同上签名,盖章,使其具有法律效应.签章有法律效应必须满足两个条件: 能够证明签名,盖章者是谁,无法抵赖 PDF合同在签章后不 ...
- 和安全有关的那些事(非对称加密、数字摘要、数字签名、数字证书、SSL、HTTPS及其他)
转自http://blog.csdn.net/bluishglc/article/details/7585965 对于一般的开发人员来说,很少需要对安全领域内的基础技术进行深入的研究,但是鉴于日常系统 ...
- 网络通信分享(一):数字签名,数字证书,https通信,数据加密
加密算法: 一:对称加密算法 在对称加密算法中,加密使用的密钥和解密使用的密钥是相同的.也就是说,加密和解密都是使用的同一个密钥.因此对称加密算法要保证安全性的话,密钥要做好保密,只能让使用的人知道, ...
- 转: https 单向双向认证说明_数字证书, 数字签名, SSL(TLS) , SASL
转自: http://www.cnblogs.com/mailingfeng/archive/2012/07/18/2597392.html 因为项目中要用到TLS + SASL 来做安全认证层. 所 ...
- RSA 非对称加密 数字签名 数字证书
什么是RSA加密算法 RSA加密算法是一种非对称加密算法,算法的数学基础是极大数分解难题. RSA加密算法的强度也就是极大数分解的难度,目前700多位(二进制)的数字已经可以破解,1024位认为是比较 ...
随机推荐
- firewalld规则配置
firewalld规则配置 一.概念 动态防火墙 启动新规则时,不会像iptables一样,先清空规则,再启动所有规则,如此会对现在程序有影响,哪怕只是一条规则.而firewalld 规则变更不需要对 ...
- MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录-3
接上文,单节点升级到80版本之后,构建新版本的80集群就水到渠成.相对简单了,详情可参见之前的集群构建博文. 本文在修改配置集群的新参数时,修改了pxc_strict_mode为默认的ENFORCIN ...
- EMC ndmp NAS
NAS 是带存储系统的专用高性能文件服务器.它可提供文件级数据访问和共享. NAS 使用网络和文件共享协议,包括用于数据传输的 TCP/IP 以及用于远程文件服务的 CIFS 和 NFS. 最简单的备 ...
- python学习笔记(持续更新)
一.对列表的操作 #建立一个列表 list = [1,2,3,4] #打印列表 print(list) #在列表尾部添加元素 list.append(5) #在指定位置插入元素 list.insert ...
- Android dumpsys介绍
目录 一.需求 二.环境 三.相关概念 3.1 dumpsys 3.2 Binder 3.3 管道 四.dumpsys指令的使用 4.1 dumpsys使用 4.2 dumpsys指令语法 五.详细设 ...
- Redis 6 学习笔记 2 —— 简单了解订阅和发布(Pub/Sub),JDK17环境下用Jedis 4.3.1连接Redis并模拟验证码发送
REDIS pubsub -- Redis中国用户组(CRUG) 什么是发布和订阅 Redis发布订阅是一种通信模式:发送者(Pub)发送消息,订阅者(Sub)接收消息.Redis客户端可以订阅任意数 ...
- C# 反序列化JSON
try { u = await WebAPIOperator.PostAsync("/v2.0/auth/user/user/login", new LoginRequestMod ...
- 2022 暑期 DP 极限单兵计划
前言 LJ 认为我的 DP 是我的一大弱项,便精心为我准备了 毒瘤DP 12 题(然后发现原来给的 T1 是个树套树,就变成 毒瘤DP 11 题 感谢 LJ 教练..... 为了方便复习,代码均格式化 ...
- OpenAI宫斗反转反转再反转,到底是资本任性还是人性扭曲?
最近OpenAI发生了一件大事,创始人山姆·奥特曼被董事会开除了,这在AI界引起了轩然大波. 事件经过 我们先来捋一下事件经过,时间以美国旧金山当地时间为准. 11月17日 11月17日12点(北京时 ...
- Python根据输入的公司编号、名称、网址,格式化输出公司信息。其中1)冒号统一为英文冒号,编号占6位,不足6位的前面补0。编号后面是制表符。
根据输入的公司编号.名称.网址,格式化输出公司信息.其中 1)冒号统一为英文冒号,编号占6位,不足6位的前面补0.编号后面是制表符. 2)"公司名称:" 后面输出字符串占8位,左对 ...