当前位置: 首页 > 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 ;
}

相关文章:

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

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

2007~2016 年税调经纬度及其所处的省市区县乡镇数据

之前给大家分享过一份税调企业经纬度及其所处的省市区县数据: 2007~2016 年税调企业地理信息数据(含经纬度及其所处的省市区县):https://rstata.duanshu.com/#/course/76d38022cd004b09b2aa09647936beb0 最近有培训班的小伙伴提出是否能根据税调企业经纬度来判断其所属的乡…...

SLAM学习入门--编程语言

文章目录 编程语言一、C/C++C 与 C++ 的区别(面向对象的特点)C++ 与 Python的区别判断struct的字节数static 作用Const 作用extern "C"的作用多态如何实现多态?虚函数虚函数怎么实现的?析构函数虚析构函数的作用virtual函数能不能用在构造函数中&#...

Go语言程序设计-第6章--方法

Go语言程序设计-第6章–方法 对象就是简单的一个值或者变量&#xff0c;并且拥有其方法&#xff0c;而方法是某种特定类型的函数。 6.1 方法的声明 方法的声明和普通函数的声明类似&#xff0c;只是在函数名字前面多了一个参数。这个参数把这个方法绑定到这个参数对应的类型…...

AI按理说应该最擅长理工,为啥先冲击文艺行业?

介绍 本人数据AI工程师&#xff0c;我的观点对全行业都有冲击&#xff0c;当AI大模型持续进化之时&#xff0c;没有一家公司能独善其身。 本文从产业架构上、论文体量、基础Pass能力、通用大模型、AI开源社区、业务属性大模型、内容消费工具、创作工具赛道、企业服务这些板块…...

蓝牙物联网移动硬件数据传输系统解决方案

随着传感器技术、网络技术和数据传输技术的不断发展&#xff0c;人们对智能设备的需求日渐增强,利用传感器技术可以对周围环境进行准确和全面的感知&#xff0c;获取到实时信息&#xff0c;从而在网络中进行传输和共享&#xff0c;再通过服务器对各种数据进行保存、分析和挖掘等…...

Linux下Web服务器工作模型及Nginx工作原理详解

文章目录 1. 工作模型概述1.1 阻塞、非阻塞、同步、异步浅析1.2 Web服务器处理并发请求的方式 2. Linux下的I/O模型2.1 常用I/O模型2.2 对比以上模型 3. Nginx工作原理3.1 Nginx基本架构3.2 Nginx代码结构3.3 Nginx工作流程3.4 Nginx缓存机制3.5 Nginx缓存工具&#xff1a;Memc…...

AJAX: 整理2:学习原生的AJAX,这边借助express框架

1. npm install express 终端直接安装 2. 测试案例&#xff1a;Hello World&#xff01; 新建一个express.js的文件&#xff0c;写入下方的内容 // 1. 引入express const express require(express)// 2. 创建服务器 const app express()// 3.创建路由规则 // request 是对请…...

二、计算机软件及其使用-文字处理软件 Word 2016

Word 2016 的功能&#xff1b;Word 2016 的启动方法和工作窗口 Word 2016 的功能 编辑功能、排版功能、表格处理功能、图形与公式处理功能、文档管理功能 Word 2016 的启动方法 桌面有就单击、任务栏有就单击、开始菜单中单击 Word 2016 的工作窗口 标题栏、功能区、工作区、状…...

Linux LVM逻辑卷

一、LVM的定义 LVM 是 Logical Volume Manager 的简称&#xff0c;译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。LVM 适合于管理大存储设备&#xff0c;并允许用户动态调整文件系统的大小。此外&#xff0c;LVM 的快照功能可以帮助我们快速备份数据。LVM 为…...

Hive生产调优介绍

1.Fetch抓取 Fetch抓取是指&#xff0c;Hive中对某些情况的查询可以不必使用MapReduce计算。例如&#xff1a;SELECT * FROM employees;在这种情况下&#xff0c;Hive可以简单地读取employee对应的存储目录下的文件&#xff0c;然后输出查询结果到控制台。 在hive-default.xml…...

如何理解鼠标点击事件在程序中的处理

在计算机用户界面中&#xff0c;鼠标点击是一个常见的交互动作。那么&#xff0c;当你按下鼠标时&#xff0c;程序是如何知道这个点击是否针对它自己的按钮的呢&#xff1f;本文将探讨鼠标点击事件在操作系统和应用程序之间的传递过程。 鼠标点击事件的捕获 当你按下鼠标按钮…...

基于JWT的用户token验证

1. 基于session的用户验证 2. 基于token的用户身份验证 3. jwt jwt代码实现方式 1. 导包 <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.18.2</version> </dependency> 2. 在登录…...

通过 conda 安装 的 detectron2

从 detectron2官网 发现预编译的版本最高支持 pytorch1.10、cuda11.3。&#xff08;2023-12-26&#xff09; 1、安装 conda 环境。 conda create --name detectron2 python3.8 2、安装 pytorch1.10 和 cuda11.3。 pip3 install torch1.10.0cu113 torchvision0.11.1cu113 torc…...

嵌入式开发——SPI OLED屏幕案例

学习目标 掌握移植方法掌握调试方式学习内容 需求 官方测试示例 选择对应的平台 测试示例中,找到芯片对应平台,我们选择的是STM32F407 修改例程 已知错误修改:...

ibm上电时序(视频内容)

...

如何在Vue.js中使用$emit进行组件通信

Vue.js是一个渐进式JavaScript框架&#xff0c;它以其简洁的数据绑定和组件系统而闻名。在构建具有多个组件层次的Vue应用时&#xff0c;组件间的通信成为一个关键的话题。Vue提供了一种名为$emit的方法&#xff0c;允许子组件向父组件发送消息。本文将详细介绍如何在Vue中使用…...

SPSS相关统计学知识精要回顾-大家都来做做

很多学生问我&#xff0c;学SPSS如果想深入学&#xff0c;那么统计学原理应该掌握到什么样的水准&#xff0c;我想说的是&#xff0c;如果真的想融会贯通&#xff0c;而不是短暂过关&#xff0c;那么应该具备一定的统计学基础&#xff0c;但是统计学知识也不是面面俱到都要去学…...

React Native 从类组件到函数组件

1. 发展趋势 React Native社区中的趋势是朝向使用函数组件&#xff08;Functional Components&#xff09;和Hooks的方向发展&#xff0c;而不是使用类组件&#xff08;Class Components&#xff09;。 React Native自推出Hooks API以来&#xff0c;函数组件和Hooks的使用变得…...

Redis 快速搭建与使用

文章目录 1. Redis 特性1.1 多种数据类型支持1.2 功能完善1.3 高性能1.4 广泛的编程语言支持1.5 使用简单1.6 活跃性高/版本迭代快1.7 I/O 多路复用模型 2. Redis发展历程3. Redis 安装3.1 源码安装3.1.1 下载源码包3.1.2 解压安装包3.1.3 切换到 Redis 目录3.1.4 编译安装 3.2…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...