ItextPdf 數字簽名,HTML轉PDF功能

 哼哼,完成這篇,這周的任務算是完成了,上篇文章主要生成了本身的證書與和密碼,這篇主要實現數字簽名及HTML轉成PDF功能。html

  今天下午把功能基本完成了,常帥走過來講,你知道簽名的解籤的原理嗎?尼瑪...不清楚,cer,crt,pfx,csr..一大堆名稱,看過轉身就忘記了。。java

  在弄功能時有幾個細節,調試了半天,第一個是將不標準的HTML轉成標準的HTML格式(就是必須是善始善終),否則itextpdf轉不了,報錯。 第二個是印章定位的問題,最後通過一遍遍調試,終於能將圖在指定的位置顯示了。node

  主要功能以下apache

     1,將HTML轉成PDFapp

     2,對此PDF進行簽名maven

     3,打印簽名。ide

   一,HContent.java 常量類,定義圖片資源的位置   ui

package com.wowoyoo.helper;
/**
 * @author hubs 
 * @version 建立時間:2017年3月22日 下午3:34:56
 * 類說明
 */
public class Content {
	
	public static String BASE 				  					= "/home/hubs/桌面/ssl/ok/";	//文件存放路徑
	/** The resulting PDF */
	public static String PDF_NEW		  					= BASE + "/test1.pdf"; // 建立的PDF
	/** The resulting PDF */
	public static String PDF_SIGNED 		  				= BASE + "/signature_1.pdf"; // 簽名的文件
	/** Info after verification of a signed PDF */
	public static String PDF_VERIFICATION		= BASE + "verify.txt"; // 簽證的信息,若是已更改,則值爲空

	public static final String PFX_PATH 				= BASE + "client.pfx";// 證書,包含密鑰

	public static final String PFX_PASS 				= "xxxxx"; // 這是簽名的密碼

	public static final String STAMP_PATH 		= BASE + "test.gif"; // 簽名的圖
	public static final String LOGO_PATH 			= BASE + "logo.png"; // 簽名的圖

	public static final String CER_PATH 				= BASE + "client.crt"; // 解答的證書,公鑰

	public static byte[] OPEN_PASSWORD 		   = "hello".getBytes(); // 密碼

	public static final String HTML_PATH		   = BASE + "test.html";

	public static final String WORD_PATH		   = BASE + "word.doc";

}

    二,HTML轉PDF類加密

package com.wowoyoo.helper;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;

import org.jsoup.Jsoup;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;

/**
 * @author hubs
 * @version 建立時間:2017年3月22日 下午3:29:21 
 *  類說明"HTML轉PDF
 */
public class HtmlToPdf {
	public static void createPdf(String HTML,String outFileName) throws IOException,DocumentException {

		Document document = new Document(PageSize.A4);
		PdfWriter pdfWriter = PdfWriter.getInstance(document,new FileOutputStream(outFileName));
		document.open();
		document.addAuthor("蝸蝸遊旅行網");
		document.addTitle("蝸蝸遊旅行網電子合同");
		document.addCreator("蝸蝸遊旅行網");
		document.addHeader("wowoyoo.com", "蝸蝸遊");
		document.addKeywords("蝸蝸遊,電子合同 ");
		document.addSubject("蝸蝸遊旅行網電子合同");

		// 標準化HTML代碼
		org.jsoup.nodes.Document _doc = Jsoup.parse(new File(HTML), "UTF-8");
		_doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);

		String _html = _doc.html();
		//HTML轉PDF
		XMLWorkerHelper.getInstance().parseXHtml(pdfWriter, document,new ByteArrayInputStream(_html.getBytes()),Charset.forName("UTF-8"), new AsianFontProvider());
		document.close();
	}
	
}


    三,中文漢字類,主要是使用了itext-asian包調試

package com.wowoyoo.helper;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;

/**
 * @author hubs
 * @version 建立時間:2017年3月21日 下午4:18:49 類說明
 */
public class AsianFontProvider extends XMLWorkerFontProvider {
	public Font getFont(final String fontname, final String encoding,
			final boolean embedded, final float size, final int style,
			final BaseColor color) {
		BaseFont bf = null;
		try {
			bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",	BaseFont.NOT_EMBEDDED);
		} catch (Exception e) {
			e.printStackTrace();
		}
		Font font = new Font(bf, size, style, color);
		font.setColor(color);
		return font;
	}
}

    四,簽名類

package com.wowoyoo.helper;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfAnnotation;
import com.itextpdf.text.pdf.PdfAppearance;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CertificateInfo;
import com.itextpdf.text.pdf.security.CertificateVerification;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.VerificationException;

/**
 * @author hubs 
 * @version 建立時間:2017年3月22日 下午3:39:42
 * 類說明
 */
public class Sign {

	//對PDF進行簽名 
	public static  void signPdf(String src, String dest) throws Exception {
		KeyStore ks 			= KeyStore.getInstance("pkcs12", "BC");
		//證書與證書密碼(不要問我是什麼意思,個人直接copy網上的....)
		ks.load(new FileInputStream(Content.PFX_PATH),Content.PFX_PASS.toCharArray());
		String alias 				=	 (String) ks.aliases().nextElement();
		PrivateKey pk		    = (PrivateKey) ks.getKey(alias, Content.PFX_PASS.toCharArray());
		Certificate[] chain  = ks.getCertificateChain(alias);
		
		//讀取須要簽名的PDF源文件
		PdfReader reader 			= new PdfReader(src);
		//寫入目標文件
		FileOutputStream os  = new FileOutputStream(dest);
		PdfStamper stamper  = PdfStamper.createSignature(reader, os, '\0');
		
		// 加密,只充許打印
		stamper.setEncryption(Content.OPEN_PASSWORD, null, PdfWriter.ALLOW_PRINTING,PdfWriter.ENCRYPTION_AES_128| PdfWriter.DO_NOT_ENCRYPT_METADATA);

		int qtyPages = reader.getNumberOfPages();
		//這個是在每一頁的印章(除最後一頁)
		Image _image = Image.getInstance(Content.LOGO_PATH);

		//這個寬度是圖片定位用的
		float _width 		= PageSize.A4.getWidth() - _image.getScaledWidth();
		
		//設置爲A4紙大小
		Rectangle _rect 	= PageSize.A4;
		Rectangle _cell 	= new Rectangle(_rect);
		
		//除了最後一頁,其餘每頁都蓋章
		for (int i = 1; i < qtyPages; i++) {
			PdfAnnotation stp 	= PdfAnnotation.createStamp(stamper.getWriter(),_cell, "蝸蝸遊旅行網", "wowoyoo.com");// 每一頁加標籤
			PdfAppearance tp 	= PdfAppearance.createAppearance(stamper.getWriter(), _rect.getWidth(), _rect.getHeight());
			_image.setAbsolutePosition(_width - 50, 50);// X:座標,Y:右下角座標
			tp.addImage(_image, true);
			stp.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp);
			stamper.addAnnotation(stp, i);
		}

		// 最後一個界面加印章
		Image _last_image 		= Image.getInstance(Content.STAMP_PATH);
		PdfAnnotation stp 		= PdfAnnotation.createStamp(stamper.getWriter(),_cell, "蝸蝸遊旅行網", "wowoyoo.com");// 每一頁加標籤
		PdfAppearance tp = PdfAppearance.createAppearance(stamper.getWriter(),_rect.getWidth(), _rect.getHeight());
		_last_image.setAbsolutePosition(_width - 150, 200);// X:座標,Y:右下角座標,這裏本身調位置
		tp.addImage(_last_image, true);
		stp.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp);
		stamper.addAnnotation(stp, qtyPages);

		
		PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
		ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
		ExternalDigest digest = new BouncyCastleDigest();
		MakeSignature.signDetached(appearance, digest, es, chain, null, null,null, 0, CryptoStandard.CMS);
	}

	//簽證簽名(這裏暫時只打印出信息,不做判斷)
	/**
	 * 打印結果以下:
	 * Signature name: Signature1
	 * Signature covers whole document: true
	 *Document revision: 1 of 1
	 *Subject: {E=[273579540@qq.com], ST=[guanxi], C=[zh], L=[guilin], OU=[wowoyoo], O=[wowoyoo], CN=[wowoyoo]}
	 * Revision modified: false
	 * Certificates verified against the KeyStore
	 * @throws Exception
	 */
	public static  void verifySignatures() throws Exception {
		KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
		ks.load(null, null);

		Certificate cert1 = getPublicCertificate();
		ks.setCertificateEntry("cacert", cert1);

		PrintWriter out 						= new PrintWriter(new FileOutputStream(Content.PDF_VERIFICATION));
		PdfReader reader 					= new PdfReader(Content.PDF_SIGNED, Content.OPEN_PASSWORD);//這裏要加上簽名的密碼
		AcroFields af 							= reader.getAcroFields();
		ArrayListnames 	= af.getSignatureNames();
		for (String name : names) {
			out.println("Signature name: " + name);
			out.println("Signature covers whole document: "+ af.signatureCoversWholeDocument(name));
			out.println("Document revision: " + af.getRevision(name) + " of "+ af.getTotalRevisions());
			PdfPKCS7 pk = af.verifySignature(name);
			Calendar cal = pk.getSignDate();
			Certificate[] pkc = pk.getCertificates();
			out.println("Subject: "+ CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
			out.println("Revision modified: " + !pk.verify());
			Listerrors = CertificateVerification.verifyCertificates(pkc, ks, null, cal);
			if (errors.size() == 0)
				out.println("Certificates verified against the KeyStore");
			else
				out.println(errors);
		}
		out.flush();
		out.close();
	}

	//公鑰證書
	private static  Certificate getPublicCertificate() throws Exception {
		FileInputStream is 			= new FileInputStream(Content.CER_PATH);
		CertificateFactory cf 		= CertificateFactory.getInstance("X.509");
		X509Certificate cert 			= (X509Certificate) cf.generateCertificate(is);
		return cert;
	}
}

    五,直接調用

package com.wowoyoo.main;

import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.wowoyoo.helper.Content;
import com.wowoyoo.helper.HtmlToPdf;
import com.wowoyoo.helper.Sign;

/**
 * @author hubs
 * @version 建立時間:2017年3月20日 下午6:03:10 類說明
 */
public class Main {

	public static void main(String[] args) throws Exception {
		Security.addProvider(new BouncyCastleProvider());

		HtmlToPdf.createPdf(Content.HTML_PATH, Content.PDF_NEW);
		Sign.signPdf(Content.PDF_NEW, Content.PDF_SIGNED);
		Sign.verifySignatures();
	}

}

上圖:

 

 

依賴類

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>wowoyoo</groupId>
	<artifactId>ConverPdf</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itextpdf</artifactId>
			<version>5.5.10</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itext-asian</artifactId>
			<version>5.2.0</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.10.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bcprov-jdk15on</artifactId>
			<version>1.56</version>
		</dependency>

		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itext-pdfa</artifactId>
			<version>5.5.10</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-ext-jdk16 -->
		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bcprov-ext-jdk16</artifactId>
			<version>1.46</version>
		</dependency>

		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itext-xtra</artifactId>
			<version>5.5.10</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcmail-jdk16 -->
		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bcmail-jdk16</artifactId>
			<version>1.46</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.bouncycastle/bctsp-jdk16 -->
		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bctsp-jdk16</artifactId>
			<version>1.46</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-scratchpad -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>3.16-beta2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.7-beta3</version>
		</dependency>

		<dependency>
			<groupId>com.itextpdf.tool</groupId>
			<artifactId>xmlworker</artifactId>
			<version>5.5.10</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.18</version>
		</dependency>
	</dependencies>
</project>

 

from : http://hihubs.com/article/274

相關文章
相關標籤/搜索