电子签章简介:
电子签章,与我们所使用的数字证书一样,是用来做为身份验证的一种手段,泛指所有以电子形式存在,依附在电子文件并与其逻辑关联,可用以辨识电子文件签署者身份,保证文件的完整性,并表示签署者同意电子文件所陈述事实的内容。一般来说,对电子签章的认定,都是从技术角度而言的。主要是指通过特定的技术方案来鉴别当事人的身份及确保交易资料内容不被篡改的安全保障措施。从广义上讲,电子签章不仅包括我们通常意义上讲的”非对称性密钥加密”,也包括计算机口令、生物笔迹辨别、指纹识别,以及新近出现的眼虹膜透视辨别法、面纹识别等。而电子签章技术作为目前最成熟的”数字签章”,是以公钥及密钥的”非对称型”密码技术制作的。电子签章是电子签名的一种表现形式,利用图像处理技术将电子签名操作转化为与纸质文件盖章操作相同的可视效果,同时利用电子签名技术保障电子信息的真实性和完整性以及签名人的不可否认性 。
不啰嗦,一言不合,直接上java代码:
目前使用大多使用两种pdfbox,itextpdf开源java类库,两个库各有优势,目前据我使用可知,pdfbox功能较为强大,但是定制性较小,itextpdf 可定制性较高 ,所以我直接使用第二种了。
先说下maven需要jar:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.49</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.49</version>
</dependency>
需要用到秘钥和证书链:url
java工具类:
public static void sign(InputStream src //需要签章的pdf文件路径
, OutputStream dest // 签完章的pdf文件路径
, InputStream p12Stream, //p12 路径
char[] password
, String reason //签名的原因,显示在pdf签名属性中,随便填
, String location, String chapterPath) //签名的地点,显示在pdf签名属性中,随便填
throws GeneralSecurityException, IOException, DocumentException {
//读取keystore ,获得私钥和证书链
//KeyStore ks = KeyStore.getInstance("PKCS12");
KeyStore ks = KeyStore.getInstance("jks");
ks.load(p12Stream, password);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, password);
Certificate[] chain = ks.getCertificateChain(alias);
//下边的步骤都是固定的,照着写就行了,没啥要解释的
// Creating the reader and the stamper,开始pdfreader
PdfReader reader = new PdfReader(src);
//目标文件输出流
//创建签章工具PdfStamper ,最后一个boolean参数
//false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
//true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
PdfStamper stamper = PdfStamper.createSignature(reader, dest, '\0', null, false);
// 获取数字签章属性对象,设定数字签章的属性
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
//设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
int pageCount = reader.getNumberOfPages();
//签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
//四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
appearance.setVisibleSignature(new Rectangle(1000, 1000, 20, 20), pageCount, "sig1");
//读取图章图片,这个image是itext包的image
Image image = Image.getInstance(chapterPath);
appearance.setSignatureGraphic(image);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
//设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
// 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
// 摘要算法
ExternalDigest digest = new BouncyCastleDigest();
// 签名算法
ExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA1, null);
// 调用itext签名方法完成pdf签章CryptoStandard.CMS 签名方式,建议采用这种
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
}
main测试类:
public static void main(String[] args) throws Exception {
String KEYSTORE="H://pcs12//houKeyStore";
char[] PASSWORD = "123456".toCharArray();//keystory密码
String SRC="H://pcs12//testPage123.pdf" ;//原始pdf
String DEST="H://pcs12//demo_signed_box.pdf" ;//签名完成的pdf
String DEST2="H://pcs12//demo_signed_itext.pdf" ;//签名完成的pdf
String chapterPath="H://pcs12//d4f894aaef66f07181e55a1b910cf4f5.jpg";//签章图片
String reason="数据不可更改";
String location="桃源乡";
PdfUtils.sign(new FileInputStream(SRC), new FileOutputStream(DEST2),
new FileInputStream(KEYSTORE), PASSWORD,
reason, location, chapterPath);
System.out.println("签章完成 ");
}
测试结果:
打开生成文件,testPage123.pdf:
可参考原创:https://blog.csdn.net/do_bset_yourself/article/details/78171897?locationNum=8&fps=1