Java暗号化技術(九)——初探SSL


にある
Java暗号化技術(8)では,RSA非対称暗号化ネットワークに基づく安全な通信をシミュレートした.ここでは、既存のセキュリティネットワーク通信であるSSLについて詳しく説明します.
    CA機関が発行する有効な証明書を構築する必要があります.ここでは、上記で生成した自己署名証明書を使用します.
zlex.cer
    ここでは、証明書を鍵ライブラリにインポートします.
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
コンソール出力:
  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:WindowsSystem 32driversetchostsファイル、
www.zlex.orgはネイティブにバインドされています.ファイルの末尾に追加
127.0.0.1       www.zlex.org.アドレスバーからアクセスhttp://www.zlex.orgまたは
pingコマンドは、ネイティブにナビゲートできればドメイン名マッピングができます.
これでtomcatを構成します.先将
zlex.keystoreはtomcatのconfディレクトリにコピーし、構成します.
server.xml.プロファイルに次の内容を追加します.
<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へのアクセスを手作業で作るには、ブラウザのこれらの機能を実現する必要があるのではないかと疑う人が多いのではないでしょうか.いらない!
次に、上記の内容では、次のコード実装を示します.
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.
対応するテストクラスを指定します.
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 + "
\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 + "
\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アクセスとほとんど変わりません.コンソール出力を見てみましょう.
<!--
  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の双方向認証を完成します!
関連リンク:Java暗号化技術(一)——BASE 64と一方向暗号化アルゴリズムMD 5&SHA&MAC Java暗号化技術(二)——対称暗号化DES&AES Java暗号化技術(三)——PBEアルゴリズムJava暗号化技術(四)——非対称暗号化アルゴリズムRSA Java暗号化技術(五)——非対称暗号化アルゴリズムの由来Java暗号化技術(六)——デジタル署名アルゴリズムDSA Java暗号化技術(七)——非対称暗号化アルゴリズム最高ECC Java暗号化技術(八)——デジタル証明書Java暗号化技術(九)——初探SSL Java暗号化技術(十)——一方向認証Java暗号化技術(十一)——双方向認証Java暗号化技術(十二)——*.PFX(*.p 12)&個人情報交換ファイル