文档章节

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

mrliuze
 mrliuze
发布于 2015/05/27 17:59
字数 3787
阅读 18
收藏 1
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双向认证!

本文转载自:http://snowolf.iteye.com/blog/397693

共有 人打赏支持
mrliuze
粉丝 13
博文 155
码字总数 12377
作品 0
浦东
程序员
私信 提问
【目录导航】JAVA零基础进阶之路

【JAVA零基础入门系列】(已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day6 Java字符串 Day7 Java输入与输出...

MFrank
06/21
0
0
keytool生成证书与Tomcat SSL配置

一、Keytool介绍 Keytool是一个Java数据证书的管理工具。Keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中在keystore里,包含两种数据: 1. 密钥实体(Key entity)...

Lofo
2014/09/16
0
0
Confluence 6 安全概述和建议概述

这个文档是针对 Confluence 的系统管理员希望对 Confluence Web应用程序安全性进行评估而设计的。这个页面将对系统的安全进行大致的描述,同时也会对 Confluence 的安全配置提供建议。作为一...

honeymose
08/03
0
0
教你做一个简单的SSL安全通讯实例

一直想就SSL安全通讯部分写一些东西,今天就和大家一起探讨一下。 首先来介绍一下什么是SSL: SSL (Secure Socket Layer) 为Netscape所研发,用以保障在Internet上数据传输的安全,利用数据加...

程序员YB
2011/12/06
0
0
【项目管理】软件项目经理须知的 Java 8 安全知识

【译者按】作为软件研发项目的项目经理,只懂项目管理知识是不够的,需要对软件技术本身有基本的了解。Java 是一种主流的系统开发语言,其安全设计对于构建安全的信息系统有至关重要的意义。...

军雷
2017/06/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

当S8遇上边缘计算:谈阿里云ENS对直播业务场景的支撑

摘要: 类似S8赛事这样的大型活动直播的特点和技术挑战是什么?为什么业务要下沉到边缘?自建边缘节点和与云服务厂商合作到底该如何选择?边缘节点服务(ENS)又是如何进行技术支撑?提供的针...

阿里云官方博客
24分钟前
5
0
supervisor安装配置

supervisor安装配置 安装 wget -c https://files.pythonhosted.org/packages/44/60/698e54b4a4a9b956b2d709b4b7b676119c833d811d53ee2500f1b5e96dc3/supervisor-3.3.4.tar.gztar -zxvf su......

jackmanwu
35分钟前
1
0
laravel定时器

民间高手: https://blog.csdn.net/zhezhebie/article/details/79205414 官方文档: https://laravel-china.org/docs/laravel/5.5/scheduling/1325...

vio小黑
57分钟前
0
0
Apache Zeppelin安装及使用

Apache Zeppelin官网:http://zeppelin.apache.org/ Apache Zeppelin介绍:A web-based notebook that enables interactive data analytics. You can make beautiful data-driven, interacti......

GordonNemo
58分钟前
5
0
关于python开发多个项目环境配置Anaconda

关于Anaconda用来管理Python的包和环境 下载并安装Anaconda 创建项目:windows键+R ==> 进入CMD => 输入conda create -n 项目名称 python=3 conda info -e 查看项目以及项目所在的位置,默认...

上官清偌
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部