Java加密技術(九)——初探SSL

Java加密技術(八)中,咱們模擬了一個基於RSA非對稱加密網絡的安全通訊。如今咱們深度瞭解一下現有的安全網絡通訊——SSL。
    咱們須要構建一個由CA機構簽發的有效證書,這裏咱們使用上文中生成的自簽名證書 zlex.cer
    這裏,咱們將證書導入到咱們的密鑰庫。

Shell代碼 複製代碼  收藏代碼
  1. keytool -import -alias www.zlex.org -file d:/zlex.cer -keystore d:/zlex.keystore  
keytool -import -alias www.zlex.org -file d:/zlex.cer -keystore d:/zlex.keystore


其中
-import表示 導入
-alias指定別名,這裏是 www.zlex.org
-file指定算法,這裏是 d:/zlex.cer
-keystore指定存儲位置,這裏是 d:/zlex.keystore
在這裏我使用的密碼爲 654321

控制檯輸出:
Console代碼 複製代碼  收藏代碼
  1. 輸入keystore密碼:  
  2. 再次輸入新密碼:  
  3. 全部者:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN  
  4. 簽發人:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN  
  5. 序列號:4a1e48df  
  6. 有效期: Thu May 28 16:18:39 CST 2009 至Wed Aug 26 16:18:39 CST 2009  
  7. 證書指紋:  
  8.          MD5:19:CA:E6:36:E2:DF:AD:96:31:97:2F:A9:AD:FC:37:6A  
  9.          SHA1:49:88:30:59:29:45:F1:69:CA:97:A9:6D:8A:CF:08:D2:C3:D5:C0:C4  
  10.          簽名算法名稱:SHA1withRSA  
  11.          版本: 3  
  12. 信任這個認證? [否]:  y  
  13. 認證已添加至keystore中  
輸入keystore密碼:
再次輸入新密碼:
全部者:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
簽發人:CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN
序列號:4a1e48df
有效期: Thu May 28 16:18:39 CST 2009 至Wed Aug 26 16:18:39 CST 2009
證書指紋:
         MD5:19:CA:E6:36:E2:DF:AD:96:31:97:2F:A9:AD:FC:37:6A
         SHA1:49:88:30:59:29:45:F1:69:CA:97:A9:6D:8A:CF:08:D2:C3:D5:C0:C4
         簽名算法名稱:SHA1withRSA
         版本: 3
信任這個認證? [否]:  y
認證已添加至keystore中


OK,最複雜的準備工做已經完成。
接下來咱們將域名 www.zlex.org定位到本機上。打開 C:\Windows\System32\drivers\etc\hosts文件,將 www.zlex.org綁定在本機上。在文件末尾追加 127.0.0.1       www.zlex.org。如今經過地址欄訪問 http://www.zlex.org,或者經過 ping命令,若是可以定位到本機,域名映射就搞定了。
如今,配置tomcat。先將 zlex.keystore拷貝到tomcat的conf目錄下,而後配置 server.xml。將以下內容加入配置文件
Xml代碼 複製代碼  收藏代碼
  1. <Connector  
  2.     SSLEnabled="true"  
  3.     URIEncoding="UTF-8"  
  4.     clientAuth="false"  
  5.     keystoreFile="conf/zlex.keystore"  
  6.     keystorePass="123456"  
  7.     maxThreads="150"  
  8.     port="443"  
  9.     protocol="HTTP/1.1"  
  10.     scheme="https"  
  11.     secure="true"  
  12.     sslProtocol="TLS" />  
<Connector
			SSLEnabled="true"
			URIEncoding="UTF-8"
			clientAuth="false"
			keystoreFile="conf/zlex.keystore"
			keystorePass="123456"
			maxThreads="150"
			port="443"
			protocol="HTTP/1.1"
			scheme="https"
			secure="true"
			sslProtocol="TLS" />

注意 clientAuth="false"測試階段,置爲 false,正式使用時建議使用 true。如今啓動tomcat,訪問 https://www.zlex.org/
顯然,證書未能經過認證,這個時候你能夠選擇安裝證書(上文中的 zlex.cer文件就是證書),做爲 受信任的根證書頒發機構導入,再次重啓瀏覽器(IE,其餘瀏覽器對於域名www.zlex.org不支持本地方式訪問),訪問 https://www.zlex.org/,你會看到地址欄中會有個小鎖 ,就說明安裝成功。全部的瀏覽器聯網操做已經在RSA加密解密系統的保護之下了。但彷佛咱們感覺不到。
這個時候不少人開始懷疑,若是咱們要手工作一個這樣的https的訪問是否是須要把瀏覽器的這些個功能都實現呢?不須要!

接着上篇內容,給出以下代碼實現:
Java代碼 複製代碼  收藏代碼
  1. import java.io.FileInputStream;  
  2. import java.security.KeyStore;  
  3. import java.security.PrivateKey;  
  4. import java.security.PublicKey;  
  5. import java.security.Signature;  
  6. import java.security.cert.Certificate;  
  7. import java.security.cert.CertificateFactory;  
  8. import java.security.cert.X509Certificate;  
  9. import java.util.Date;  
  10.   
  11. import javax.crypto.Cipher;  
  12. import javax.net.ssl.HttpsURLConnection;  
  13. import javax.net.ssl.KeyManagerFactory;  
  14. import javax.net.ssl.SSLContext;  
  15. import javax.net.ssl.SSLSocketFactory;  
  16. import javax.net.ssl.TrustManagerFactory;  
  17.   
  18. /** 
  19.  * 證書組件 
  20.  *  
  21.  * @author 樑棟 
  22.  * @version 1.0 
  23.  * @since 1.0 
  24.  */  
  25. public abstract class CertificateCoder extends Coder {  
  26.   
  27.     /** 
  28.      * Java密鑰庫(Java Key Store,JKS)KEY_STORE 
  29.      */  
  30.     public static final String KEY_STORE = "JKS";  
  31.   
  32.     public static final String X509 = "X.509";  
  33.     public static final String SunX509 = "SunX509";  
  34.     public static final String SSL = "SSL";  
  35.   
  36.     /** 
  37.      * 由KeyStore得到私鑰 
  38.      *  
  39.      * @param keyStorePath 
  40.      * @param alias 
  41.      * @param password 
  42.      * @return 
  43.      * @throws Exception 
  44.      */  
  45.     private static PrivateKey getPrivateKey(String keyStorePath, String alias,  
  46.             String password) throws Exception {  
  47.         KeyStore ks = getKeyStore(keyStorePath, password);  
  48.         PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());  
  49.         return key;  
  50.     }  
  51.   
  52.     /** 
  53.      * 由Certificate得到公鑰 
  54.      *  
  55.      * @param certificatePath 
  56.      * @return 
  57.      * @throws Exception 
  58.      */  
  59.     private static PublicKey getPublicKey(String certificatePath)  
  60.             throws Exception {  
  61.         Certificate certificate = getCertificate(certificatePath);  
  62.         PublicKey key = certificate.getPublicKey();  
  63.         return key;  
  64.     }  
  65.   
  66.     /** 
  67.      * 得到Certificate 
  68.      *  
  69.      * @param certificatePath 
  70.      * @return 
  71.      * @throws Exception 
  72.      */  
  73.     private static Certificate getCertificate(String certificatePath)  
  74.             throws Exception {  
  75.         CertificateFactory certificateFactory = CertificateFactory  
  76.                 .getInstance(X509);  
  77.         FileInputStream in = new FileInputStream(certificatePath);  
  78.   
  79.         Certificate certificate = certificateFactory.generateCertificate(in);  
  80.         in.close();  
  81.   
  82.         return certificate;  
  83.     }  
  84.   
  85.     /** 
  86.      * 得到Certificate 
  87.      *  
  88.      * @param keyStorePath 
  89.      * @param alias 
  90.      * @param password 
  91.      * @return 
  92.      * @throws Exception 
  93.      */  
  94.     private static Certificate getCertificate(String keyStorePath,  
  95.             String alias, String password) throws Exception {  
  96.         KeyStore ks = getKeyStore(keyStorePath, password);  
  97.         Certificate certificate = ks.getCertificate(alias);  
  98.   
  99.         return certificate;  
  100.     }  
  101.   
  102.     /** 
  103.      * 得到KeyStore 
  104.      *  
  105.      * @param keyStorePath 
  106.      * @param password 
  107.      * @return 
  108.      * @throws Exception 
  109.      */  
  110.     private static KeyStore getKeyStore(String keyStorePath, String password)  
  111.             throws Exception {  
  112.         FileInputStream is = new FileInputStream(keyStorePath);  
  113.         KeyStore ks = KeyStore.getInstance(KEY_STORE);  
  114.         ks.load(is, password.toCharArray());  
  115.         is.close();  
  116.         return ks;  
  117.     }  
  118.   
  119.     /** 
  120.      * 私鑰加密 
  121.      *  
  122.      * @param data 
  123.      * @param keyStorePath 
  124.      * @param alias 
  125.      * @param password 
  126.      * @return 
  127.      * @throws Exception 
  128.      */  
  129.     public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,  
  130.             String alias, String password) throws Exception {  
  131.         // 取得私鑰  
  132.         PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);  
  133.   
  134.         // 對數據加密  
  135.         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());  
  136.         cipher.init(Cipher.ENCRYPT_MODE, privateKey);  
  137.   
  138.         return cipher.doFinal(data);  
  139.   
  140.     }  
  141.   
  142.     /** 
  143.      * 私鑰解密 
  144.      *  
  145.      * @param data 
  146.      * @param keyStorePath 
  147.      * @param alias 
  148.      * @param password 
  149.      * @return 
  150.      * @throws Exception 
  151.      */  
  152.     public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,  
  153.             String alias, String password) throws Exception {  
  154.         // 取得私鑰  
  155.         PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);  
  156.   
  157.         // 對數據加密  
  158.         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());  
  159.         cipher.init(Cipher.DECRYPT_MODE, privateKey);  
  160.   
  161.         return cipher.doFinal(data);  
  162.   
  163.     }  
  164.   
  165.     /** 
  166.      * 公鑰加密 
  167.      *  
  168.      * @param data 
  169.      * @param certificatePath 
  170.      * @return 
  171.      * @throws Exception 
  172.      */  
  173.     public static byte[] encryptByPublicKey(byte[] data, String certificatePath)  
  174.             throws Exception {  
  175.   
  176.         // 取得公鑰  
  177.         PublicKey publicKey = getPublicKey(certificatePath);  
  178.         // 對數據加密  
  179.         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());  
  180.         cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
  181.   
  182.         return cipher.doFinal(data);  
  183.   
  184.     }  
  185.   
  186.     /** 
  187.      * 公鑰解密 
  188.      *  
  189.      * @param data 
  190.      * @param certificatePath 
  191.      * @return 
  192.      * @throws Exception 
  193.      */  
  194.     public static byte[] decryptByPublicKey(byte[] data, String certificatePath)  
  195.             throws Exception {  
  196.         // 取得公鑰  
  197.         PublicKey publicKey = getPublicKey(certificatePath);  
  198.   
  199.         // 對數據加密  
  200.         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());  
  201.         cipher.init(Cipher.DECRYPT_MODE, publicKey);  
  202.   
  203.         return cipher.doFinal(data);  
  204.   
  205.     }  
  206.   
  207.     /** 
  208.      * 驗證Certificate 
  209.      *  
  210.      * @param certificatePath 
  211.      * @return 
  212.      */  
  213.     public static boolean verifyCertificate(String certificatePath) {  
  214.         return verifyCertificate(new Date(), certificatePath);  
  215.     }  
  216.   
  217.     /** 
  218.      * 驗證Certificate是否過時或無效 
  219.      *  
  220.      * @param date 
  221.      * @param certificatePath 
  222.      * @return 
  223.      */  
  224.     public static boolean verifyCertificate(Date date, String certificatePath) {  
  225.         boolean status = true;  
  226.         try {  
  227.             // 取得證書  
  228.             Certificate certificate = getCertificate(certificatePath);  
  229.             // 驗證證書是否過時或無效  
  230.             status = verifyCertificate(date, certificate);  
  231.         } catch (Exception e) {  
  232.             status = false;  
  233.         }  
  234.         return status;  
  235.     }  
  236.   
  237.     /** 
  238.      * 驗證證書是否過時或無效 
  239.      *  
  240.      * @param date 
  241.      * @param certificate 
  242.      * @return 
  243.      */  
  244.     private static boolean verifyCertificate(Date date, Certificate certificate) {  
  245.         boolean status = true;  
  246.         try {  
  247.             X509Certificate x509Certificate = (X509Certificate) certificate;  
  248.             x509Certificate.checkValidity(date);  
  249.         } catch (Exception e) {  
  250.             status = false;  
  251.         }  
  252.         return status;  
  253.     }  
  254.   
  255.     /** 
  256.      * 簽名 
  257.      *  
  258.      * @param keyStorePath 
  259.      * @param alias 
  260.      * @param password 
  261.      *  
  262.      * @return 
  263.      * @throws Exception 
  264.      */  
  265.     public static String sign(byte[] sign, String keyStorePath, String alias,  
  266.             String password) throws Exception {  
  267.         // 得到證書  
  268.         X509Certificate x509Certificate = (X509Certificate) getCertificate(  
  269.                 keyStorePath, alias, password);  
  270.         // 獲取私鑰  
  271.         KeyStore ks = getKeyStore(keyStorePath, password);  
  272.         // 取得私鑰  
  273.         PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password  
  274.                 .toCharArray());  
  275.   
  276.         // 構建簽名  
  277.         Signature signature = Signature.getInstance(x509Certificate  
  278.                 .getSigAlgName());  
  279.         signature.initSign(privateKey);  
  280.         signature.update(sign);  
  281.         return encryptBASE64(signature.sign());  
  282.     }  
  283.   
  284.     /** 
  285.      * 驗證簽名 
  286.      *  
  287.      * @param data 
  288.      * @param sign 
  289.      * @param certificatePath 
  290.      * @return 
  291.      * @throws Exception 
  292.      */  
  293.     public static boolean verify(byte[] data, String sign,  
  294.             String certificatePath) throws Exception {  
  295.         // 得到證書  
  296.         X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);  
  297.         // 得到公鑰  
  298.         PublicKey publicKey = x509Certificate.getPublicKey();  
  299.         // 構建簽名  
  300.         Signature signature = Signature.getInstance(x509Certificate  
  301.                 .getSigAlgName());  
  302.         signature.initVerify(publicKey);  
  303.         signature.update(data);  
  304.   
  305.         return signature.verify(decryptBASE64(sign));  
  306.   
  307.     }  
  308.   
  309.     /** 
  310.      * 驗證Certificate 
  311.      *  
  312.      * @param keyStorePath 
  313.      * @param alias 
  314.      * @param password 
  315.      * @return 
  316.      */  
  317.     public static boolean verifyCertificate(Date date, String keyStorePath,  
  318.             String alias, String password) {  
  319.         boolean status = true;  
  320.         try {  
  321.             Certificate certificate = getCertificate(keyStorePath, alias,  
  322.                     password);  
  323.             status = verifyCertificate(date, certificate);  
  324.         } catch (Exception e) {  
  325.             status = false;  
  326.         }  
  327.         return status;  
  328.     }  
  329.   
  330.     /** 
  331.      * 驗證Certificate 
  332.      *  
  333.      * @param keyStorePath 
  334.      * @param alias 
  335.      * @param password 
  336.      * @return 
  337.      */  
  338.     public static boolean verifyCertificate(String keyStorePath, String alias,  
  339.             String password) {  
  340.         return verifyCertificate(new Date(), keyStorePath, alias, password);  
  341.     }  
  342.   
  343.     /** 
  344.      * 得到SSLSocektFactory 
  345.      *  
  346.      * @param password 
  347.      *            密碼 
  348.      * @param keyStorePath 
  349.      *            密鑰庫路徑 
  350.      *  
  351.      * @param trustKeyStorePath 
  352.      *            信任庫路徑 
  353.      * @return 
  354.      * @throws Exception 
  355.      */  
  356.     private static SSLSocketFactory getSSLSocketFactory(String password,  
  357.             String keyStorePath, String trustKeyStorePath) throws Exception {  
  358.         // 初始化密鑰庫  
  359.         KeyManagerFactory keyManagerFactory = KeyManagerFactory  
  360.                 .getInstance(SunX509);  
  361.         KeyStore keyStore = getKeyStore(keyStorePath, password);  
  362.         keyManagerFactory.init(keyStore, password.toCharArray());  
  363.   
  364.         // 初始化信任庫  
  365.         TrustManagerFactory trustManagerFactory = TrustManagerFactory  
  366.                 .getInstance(SunX509);  
  367.         KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);  
  368.         trustManagerFactory.init(trustkeyStore);  
  369.   
  370.         // 初始化SSL上下文  
  371.         SSLContext ctx = SSLContext.getInstance(SSL);  
  372.         ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory  
  373.                 .getTrustManagers(), null);  
  374.         SSLSocketFactory sf = ctx.getSocketFactory();  
  375.   
  376.         return sf;  
  377.     }  
  378.   
  379.     /** 
  380.      * 爲HttpsURLConnection配置SSLSocketFactory 
  381.      *  
  382.      * @param conn 
  383.      *            HttpsURLConnection 
  384.      * @param password 
  385.      *            密碼 
  386.      * @param keyStorePath 
  387.      *            密鑰庫路徑 
  388.      *  
  389.      * @param trustKeyStorePath 
  390.      *            信任庫路徑 
  391.      * @throws Exception 
  392.      */  
  393.     public static void configSSLSocketFactory(HttpsURLConnection conn,  
  394.             String password, String keyStorePath, String trustKeyStorePath)  
  395.             throws Exception {  
  396.         conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,  
  397.                 trustKeyStorePath));  
  398.     }  
  399. }  
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.crypto.Cipher;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
 * 證書組件
 * 
 * @author 樑棟
 * @version 1.0
 * @since 1.0
 */
public abstract class CertificateCoder extends Coder {

	/**
	 * Java密鑰庫(Java Key Store,JKS)KEY_STORE
	 */
	public static final String KEY_STORE = "JKS";

	public static final String X509 = "X.509";
	public static final String SunX509 = "SunX509";
	public static final String SSL = "SSL";

	/**
	 * 由KeyStore得到私鑰
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static PrivateKey getPrivateKey(String keyStorePath, String alias,
			String password) throws Exception {
		KeyStore ks = getKeyStore(keyStorePath, password);
		PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
		return key;
	}

	/**
	 * 由Certificate得到公鑰
	 * 
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	private static PublicKey getPublicKey(String certificatePath)
			throws Exception {
		Certificate certificate = getCertificate(certificatePath);
		PublicKey key = certificate.getPublicKey();
		return key;
	}

	/**
	 * 得到Certificate
	 * 
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	private static Certificate getCertificate(String certificatePath)
			throws Exception {
		CertificateFactory certificateFactory = CertificateFactory
				.getInstance(X509);
		FileInputStream in = new FileInputStream(certificatePath);

		Certificate certificate = certificateFactory.generateCertificate(in);
		in.close();

		return certificate;
	}

	/**
	 * 得到Certificate
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static Certificate getCertificate(String keyStorePath,
			String alias, String password) throws Exception {
		KeyStore ks = getKeyStore(keyStorePath, password);
		Certificate certificate = ks.getCertificate(alias);

		return certificate;
	}

	/**
	 * 得到KeyStore
	 * 
	 * @param keyStorePath
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static KeyStore getKeyStore(String keyStorePath, String password)
			throws Exception {
		FileInputStream is = new FileInputStream(keyStorePath);
		KeyStore ks = KeyStore.getInstance(KEY_STORE);
		ks.load(is, password.toCharArray());
		is.close();
		return ks;
	}

	/**
	 * 私鑰加密
	 * 
	 * @param data
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
			String alias, String password) throws Exception {
		// 取得私鑰
		PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

		// 對數據加密
		Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);

		return cipher.doFinal(data);

	}

	/**
	 * 私鑰解密
	 * 
	 * @param data
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
			String alias, String password) throws Exception {
		// 取得私鑰
		PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

		// 對數據加密
		Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateKey);

		return cipher.doFinal(data);

	}

	/**
	 * 公鑰加密
	 * 
	 * @param data
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
			throws Exception {

		// 取得公鑰
		PublicKey publicKey = getPublicKey(certificatePath);
		// 對數據加密
		Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);

		return cipher.doFinal(data);

	}

	/**
	 * 公鑰解密
	 * 
	 * @param data
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
			throws Exception {
		// 取得公鑰
		PublicKey publicKey = getPublicKey(certificatePath);

		// 對數據加密
		Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, publicKey);

		return cipher.doFinal(data);

	}

	/**
	 * 驗證Certificate
	 * 
	 * @param certificatePath
	 * @return
	 */
	public static boolean verifyCertificate(String certificatePath) {
		return verifyCertificate(new Date(), certificatePath);
	}

	/**
	 * 驗證Certificate是否過時或無效
	 * 
	 * @param date
	 * @param certificatePath
	 * @return
	 */
	public static boolean verifyCertificate(Date date, String certificatePath) {
		boolean status = true;
		try {
			// 取得證書
			Certificate certificate = getCertificate(certificatePath);
			// 驗證證書是否過時或無效
			status = verifyCertificate(date, certificate);
		} catch (Exception e) {
			status = false;
		}
		return status;
	}

	/**
	 * 驗證證書是否過時或無效
	 * 
	 * @param date
	 * @param certificate
	 * @return
	 */
	private static boolean verifyCertificate(Date date, Certificate certificate) {
		boolean status = true;
		try {
			X509Certificate x509Certificate = (X509Certificate) certificate;
			x509Certificate.checkValidity(date);
		} catch (Exception e) {
			status = false;
		}
		return status;
	}

	/**
	 * 簽名
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] sign, String keyStorePath, String alias,
			String password) throws Exception {
		// 得到證書
		X509Certificate x509Certificate = (X509Certificate) getCertificate(
				keyStorePath, alias, password);
		// 獲取私鑰
		KeyStore ks = getKeyStore(keyStorePath, password);
		// 取得私鑰
		PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
				.toCharArray());

		// 構建簽名
		Signature signature = Signature.getInstance(x509Certificate
				.getSigAlgName());
		signature.initSign(privateKey);
		signature.update(sign);
		return encryptBASE64(signature.sign());
	}

	/**
	 * 驗證簽名
	 * 
	 * @param data
	 * @param sign
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	public static boolean verify(byte[] data, String sign,
			String certificatePath) throws Exception {
		// 得到證書
		X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
		// 得到公鑰
		PublicKey publicKey = x509Certificate.getPublicKey();
		// 構建簽名
		Signature signature = Signature.getInstance(x509Certificate
				.getSigAlgName());
		signature.initVerify(publicKey);
		signature.update(data);

		return signature.verify(decryptBASE64(sign));

	}

	/**
	 * 驗證Certificate
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 */
	public static boolean verifyCertificate(Date date, String keyStorePath,
			String alias, String password) {
		boolean status = true;
		try {
			Certificate certificate = getCertificate(keyStorePath, alias,
					password);
			status = verifyCertificate(date, certificate);
		} catch (Exception e) {
			status = false;
		}
		return status;
	}

	/**
	 * 驗證Certificate
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 */
	public static boolean verifyCertificate(String keyStorePath, String alias,
			String password) {
		return verifyCertificate(new Date(), keyStorePath, alias, password);
	}

	/**
	 * 得到SSLSocektFactory
	 * 
	 * @param password
	 *            密碼
	 * @param keyStorePath
	 *            密鑰庫路徑
	 * 
	 * @param trustKeyStorePath
	 *            信任庫路徑
	 * @return
	 * @throws Exception
	 */
	private static SSLSocketFactory getSSLSocketFactory(String password,
			String keyStorePath, String trustKeyStorePath) throws Exception {
		// 初始化密鑰庫
		KeyManagerFactory keyManagerFactory = KeyManagerFactory
				.getInstance(SunX509);
		KeyStore keyStore = getKeyStore(keyStorePath, password);
		keyManagerFactory.init(keyStore, password.toCharArray());

		// 初始化信任庫
		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(SunX509);
		KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);
		trustManagerFactory.init(trustkeyStore);

		// 初始化SSL上下文
		SSLContext ctx = SSLContext.getInstance(SSL);
		ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
				.getTrustManagers(), null);
		SSLSocketFactory sf = ctx.getSocketFactory();

		return sf;
	}

	/**
	 * 爲HttpsURLConnection配置SSLSocketFactory
	 * 
	 * @param conn
	 *            HttpsURLConnection
	 * @param password
	 *            密碼
	 * @param keyStorePath
	 *            密鑰庫路徑
	 * 
	 * @param trustKeyStorePath
	 *            信任庫路徑
	 * @throws Exception
	 */
	public static void configSSLSocketFactory(HttpsURLConnection conn,
			String password, String keyStorePath, String trustKeyStorePath)
			throws Exception {
		conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,
				trustKeyStorePath));
	}
}


增長了 configSSLSocketFactory方法供外界調用,該方法爲HttpsURLConnection配置了SSLSocketFactory。當HttpsURLConnection配置了SSLSocketFactory後,咱們就能夠經過HttpsURLConnection的getInputStream、getOutputStream,像往常使用HttpURLConnection作操做了。尤爲要說明一點,未配置SSLSocketFactory前,HttpsURLConnection的getContentLength()得到值永遠都是 -1

給出相應測試類:
Java代碼 複製代碼  收藏代碼
  1. import static org.junit.Assert.*;  
  2.   
  3. import java.io.DataInputStream;  
  4. import java.io.InputStream;  
  5. import java.net.URL;  
  6.   
  7. import javax.net.ssl.HttpsURLConnection;  
  8.   
  9. import org.junit.Test;  
  10.   
  11. /** 
  12.  *  
  13.  * @author 樑棟 
  14.  * @version 1.0 
  15.  * @since 1.0 
  16.  */  
  17. public class CertificateCoderTest {  
  18.     private String password = "123456";  
  19.     private String alias = "www.zlex.org";  
  20.     private String certificatePath = "d:/zlex.cer";  
  21.     private String keyStorePath = "d:/zlex.keystore";  
  22.     private String clientKeyStorePath = "d:/zlex-client.keystore";  
  23.     private String clientPassword = "654321";  
  24.   
  25.     @Test  
  26.     public void test() throws Exception {  
  27.         System.err.println("公鑰加密——私鑰解密");  
  28.         String inputStr = "Ceritifcate";  
  29.         byte[] data = inputStr.getBytes();  
  30.   
  31.         byte[] encrypt = CertificateCoder.encryptByPublicKey(data,  
  32.                 certificatePath);  
  33.   
  34.         byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,  
  35.                 keyStorePath, alias, password);  
  36.         String outputStr = new String(decrypt);  
  37.   
  38.         System.err.println("加密前: " + inputStr + "\n\r" + "解密後: " + outputStr);  
  39.   
  40.         // 驗證數據一致  
  41.         assertArrayEquals(data, decrypt);  
  42.   
  43.         // 驗證證書有效  
  44.         assertTrue(CertificateCoder.verifyCertificate(certificatePath));  
  45.   
  46.     }  
  47.   
  48.     @Test  
  49.     public void testSign() throws Exception {  
  50.         System.err.println("私鑰加密——公鑰解密");  
  51.   
  52.         String inputStr = "sign";  
  53.         byte[] data = inputStr.getBytes();  
  54.   
  55.         byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,  
  56.                 keyStorePath, alias, password);  
  57.   
  58.         byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,  
  59.                 certificatePath);  
  60.   
  61.         String outputStr = new String(decodedData);  
  62.         System.err.println("加密前: " + inputStr + "\n\r" + "解密後: " + outputStr);  
  63.         assertEquals(inputStr, outputStr);  
  64.   
  65.         System.err.println("私鑰簽名——公鑰驗證簽名");  
  66.         // 產生簽名  
  67.         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,  
  68.                 password);  
  69.         System.err.println("簽名:\r" + sign);  
  70.   
  71.         // 驗證簽名  
  72.         boolean status = CertificateCoder.verify(encodedData, sign,  
  73.                 certificatePath);  
  74.         System.err.println("狀態:\r" + status);  
  75.         assertTrue(status);  
  76.   
  77.     }  
  78.   
  79.     @Test  
  80.     public void testHttps() throws Exception {  
  81.         URL url = new URL("https://www.zlex.org/examples/");  
  82.         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();  
  83.   
  84.         conn.setDoInput(true);  
  85.         conn.setDoOutput(true);  
  86.   
  87.         CertificateCoder.configSSLSocketFactory(conn, clientPassword,  
  88.                 clientKeyStorePath, clientKeyStorePath);  
  89.   
  90.         InputStream is = conn.getInputStream();  
  91.   
  92.         int length = conn.getContentLength();  
  93.   
  94.         DataInputStream dis = new DataInputStream(is);  
  95.         byte[] data = new byte[length];  
  96.         dis.readFully(data);  
  97.   
  98.         dis.close();  
  99.         System.err.println(new String(data));  
  100.         conn.disconnect();  
  101.     }  
  102. }  
import static org.junit.Assert.*;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import org.junit.Test;

/**
 * 
 * @author 樑棟
 * @version 1.0
 * @since 1.0
 */
public class CertificateCoderTest {
	private String password = "123456";
	private String alias = "www.zlex.org";
	private String certificatePath = "d:/zlex.cer";
	private String keyStorePath = "d:/zlex.keystore";
	private String clientKeyStorePath = "d:/zlex-client.keystore";
	private String clientPassword = "654321";

	@Test
	public void test() throws Exception {
		System.err.println("公鑰加密——私鑰解密");
		String inputStr = "Ceritifcate";
		byte[] data = inputStr.getBytes();

		byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
				certificatePath);

		byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
				keyStorePath, alias, password);
		String outputStr = new String(decrypt);

		System.err.println("加密前: " + inputStr + "\n\r" + "解密後: " + outputStr);

		// 驗證數據一致
		assertArrayEquals(data, decrypt);

		// 驗證證書有效
		assertTrue(CertificateCoder.verifyCertificate(certificatePath));

	}

	@Test
	public void testSign() throws Exception {
		System.err.println("私鑰加密——公鑰解密");

		String inputStr = "sign";
		byte[] data = inputStr.getBytes();

		byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
				keyStorePath, alias, password);

		byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
				certificatePath);

		String outputStr = new String(decodedData);
		System.err.println("加密前: " + inputStr + "\n\r" + "解密後: " + outputStr);
		assertEquals(inputStr, outputStr);

		System.err.println("私鑰簽名——公鑰驗證簽名");
		// 產生簽名
		String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
				password);
		System.err.println("簽名:\r" + sign);

		// 驗證簽名
		boolean status = CertificateCoder.verify(encodedData, sign,
				certificatePath);
		System.err.println("狀態:\r" + status);
		assertTrue(status);

	}

	@Test
	public void testHttps() throws Exception {
		URL url = new URL("https://www.zlex.org/examples/");
		HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

		conn.setDoInput(true);
		conn.setDoOutput(true);

		CertificateCoder.configSSLSocketFactory(conn, clientPassword,
				clientKeyStorePath, clientKeyStorePath);

		InputStream is = conn.getInputStream();

		int length = conn.getContentLength();

		DataInputStream dis = new DataInputStream(is);
		byte[] data = new byte[length];
		dis.readFully(data);

		dis.close();
		System.err.println(new String(data));
		conn.disconnect();
	}
}

注意 testHttps方法,幾乎和咱們往常作HTTP訪問沒有差異,咱們來看控制檯輸出:
Console代碼 複製代碼  收藏代碼
  1. <!--  
  2.   Licensed to the Apache Software Foundation (ASF) under one or more  
  3.   contributor license agreements.  See the NOTICE file distributed with  
  4.   this work for additional information regarding copyright ownership.  
  5.   The ASF licenses this file to You under the Apache License, Version 2.0  
  6.   (the "License"); you may not use this file except in compliance with  
  7.   the License.  You may obtain a copy of the License at  
  8.   
  9.       http://www.apache.org/licenses/LICENSE-2.0  
  10.   
  11.   Unless required by applicable law or agreed to in writing, software  
  12.   distributed under the License is distributed on an "AS IS" BASIS,  
  13.   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  14.   See the License for the specific language governing permissions and  
  15.   limitations under the License.  
  16. -->  
  17. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">  
  18. <HTML><HEAD><TITLE>Apache Tomcat Examples</TITLE>  
  19. <META http-equiv=Content-Type content="text/html">  
  20. </HEAD>  
  21. <BODY>  
  22. <P>  
  23. <H3>Apache Tomcat Examples</H3>  
  24. <P></P>  
  25. <ul>  
  26. <li><a href="servlets">Servlets examples</a></li>  
  27. <li><a href="jsp">JSP Examples</a></li>  
  28. </ul>  
  29. </BODY></HTML>  
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Apache Tomcat Examples</TITLE>
<META http-equiv=Content-Type content="text/html">
</HEAD>
<BODY>
<P>
<H3>Apache Tomcat Examples</H3>
<P></P>
<ul>
<li><a href="servlets">Servlets examples</a></li>
<li><a href="jsp">JSP Examples</a></li>
</ul>
</BODY></HTML>

經過瀏覽器直接訪問 https://www.zlex.org/examples/你也會得到上述內容。也就是說應用甲方做爲服務器構建tomcat服務,乙方能夠經過上述方式訪問甲方受保護的SSL應用,而且不須要考慮具體的加密解密問題。甲乙雙方能夠通過相應配置,經過雙方的tomcat配置有效的SSL服務,簡化上述代碼實現,徹底經過證書配置完成SSL雙向認證!
相關文章
相關標籤/搜索