电子签章,与我们所使用的数字证书一样,是用来做为身份验证的一种手段,泛指所有以电子形式存在,依附在电子文件并与其逻辑关联,可用以辨识电子文件签署者身份,保证文件的完整性,并表示签署者同意电子文件所陈述事实的内容。一般来说,对电子签章的认定,都是从技术角度而言的。主要是指通过特定的技术方案来鉴别当事人的身份及确保交易资料内容不被篡改的安全保障措施。从广义上讲,电子签章不仅包括我们通常意义上讲的”非对称性密钥加密”,也包括计算机口令、生物笔迹辨别、指纹识别,以及新近出现的眼虹膜透视辨别法、面纹识别等。而电子签章技术作为目前最成熟的”数字签章”,是以公钥及密钥的”非对称型”密码技术制作的。电子签章是电子签名的一种表现形式,利用图像处理技术将电子签名操作转化为与纸质文件盖章操作相同的可视效果,同时利用电子签名技术保障电子信息的真实性和完整性以及签名人的不可否认性 。
如果对数字证书,签名验签,摘要,数据签名不太理解的同学,可以参考我之前的文章
安全之加密算法(-)
openssl 自建ca,颁发客户端证书
具体了解下
java 操作pdf的开源类库我大概了解了两种pdfbox,itextpdf,两个库各有优势,目前据我使用可知,pdfbox功能较为强大,但是定制性较小,itextpdf 可定制性较高
准备
p12 证书
测试电子签章图片
itextpdf 提供了 MakeSignature 这个入口类,操作相对较为简单
封装下即可
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");
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);
//设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
//签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
//四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
appearance.setVisibleSignature(new Rectangle(0, 800, 100, 700), 1, "sig1");
//读取图章图片,这个image是itext包的image
Image image = Image.getInstance(chapterPath);
appearance.setSignatureGraphic(image);
appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
//设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
appearance.setRenderingMode(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, CryptoStandard.CMS);
}
pdfbox 实现签名可以从pdfbox 官网示例中找到
svn地址
https://svn.apache.org/repos/asf/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/
简单封装示例
public static void sign(char[] password,InputStream p12Input,FileInputStream imageStream,File srcPdf,File signed,String signerName,String reason,String location) throws Exception{
boolean externalSig=false;
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(p12Input, password);
PdfSignBox signing = new PdfSignBox(keystore, password);
File signedDocumentFile;
int page=1;
signing.setVisibleSignDesigner(srcPdf.toString(), 50, 100, -90, imageStream, page);
signing.setVisibleSignatureProperties(signerName, location, reason, 0, page, true);
signing.setExternalSigning(externalSig);
signing.signPDF(srcPdf, signed, null);
}
签名测试代码
package com.taoyuan.pdf.sign.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import com.taoyuan.pdf.sign.itext.PdfSignBox;
import com.taoyuan.pdf.sign.itext.PdfSignItext;
public class Test {
public static void main(String[] args) throws Exception {
String KEYSTORE="d://test.p12";
char[] PASSWORD = "123".toCharArray();//keystory密码
String SRC="d://demo.pdf" ;//原始pdf
String DEST="d://demo_signed_box.pdf" ;//签名完成的pdf
String DEST2="d://demo_signed_itext.pdf" ;//签名完成的pdf
String chapterPath="d://chapter.png";//签章图片
String signername="測試";
String reason="数据不可更改";
String location="桃源乡";
PdfSignBox.sign(PASSWORD, new FileInputStream(KEYSTORE),
new FileInputStream(chapterPath),
new File(SRC),new File(DEST),signername, reason, location);
PdfSignItext.sign(new FileInputStream(SRC), new FileOutputStream(DEST2),
new FileInputStream(KEYSTORE), PASSWORD,
reason, location, chapterPath);
}
}
当然自己生成的证书去给pdf签章,是不被认可的,这种证书需要花钱的,大概1000多元一年吧
完整代码下载地址
http://download.csdn.net/download/do_bset_yourself/10010394