JAva SSL簡単操作demo
SSL process :http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks
1.クライアントサーバ交渉で利用可能な暗号化スイート:
クライアントとサーバが開始したSSLセッションで、クライアントは、サーバがサポートしている暗号化スイートのリストを通知するメッセージを送信します.
SSLSocket.getSupportedCipherSuites()を選択し、サーバがより良い暗号化スイートを選択します.
2、Authenticating the Server(認証サーバー)
このステップは、実質的にクライアント認証サーバ、すなわち、クライアントがコミュニケーション中のサーバを信頼するかどうかを選択するかどうかであり、実際にはオプションである.
サーバは自分が主張するアイデンティティであることを証明するために,クライアントに自分の「public key certificate」を提示する必要がある.
公開鍵証明書は、証明書が有効であれば、クライアントがサーバのアイデンティティを確認することができます.
サーバはクライアントと情報を交換し、双方がRSAなどのsecret keyに同意するようにし、クライアントはサーバが提示した証明書からpublic keyを取得し、secret key informationを暗号化し、次に暗号化された情報をサーバに送信し、サーバは自分のprivate keyを利用して情報を復号し、クライアントを認証する.
3、Sending the Encrypted Data
Both the client and the server now have access to the same secret key. With each message, they use the cryptographic hash function, chosen in the first step of this process, and shared secret information, to compute an HMAC that they append to the message. They then use the secret key and the secret key algorithm negotiated in the first step of this process to encrypt the secure data and the HMAC. The client and server can now communicate securely using their encrypted and hashed data.
以下はsslメッセージの図です.
The SSL messages are sent in the following order: Client hello - The client sends the server information including the highest version of SSL it supports and a list of the cipher suites it supports. (TLS 1.0 is indicated as SSL 3.1.) The cipher suite information includes cryptographic algorithms and key sizes. Server hello - The server chooses the highest version of SSL and the best cipher suite that both the client and server support and sends this information to the client. Certificate - The server sends the client a certificate or a certificate chain. A certificate chain typically begins with the server's public key certificate and ends with the certificate authority's root certificate. This message is optional, but is used whenever server authentication is required. Certificate request - If the server needs to authenticate the client, it sends the client a certificate request. In Internet applications, this message is rarely sent. Server key exchange - The server sends the client a server key exchange message when the public key information sent in message 3 above is not sufficient for key exchange. For example, in ciphersuites based on Diffie-Hellman, this message contains the server's DH public key. Server hello done - The server tells the client that it is finished with its initial negotiation messages. Certificate - If the server requests a certificate from the client in message 4, the client sends its certificate chain, just as the server did in message 3.Note: Only a few Internet server applications ask for a certificate from the client. Client key exchange - The client generates information used to create a key to use for symmetric encryption. For RSA, the client then encrypts this key information with the server's public key and sends it to the server. For ciphersuites based on Diffie-Hellman, this message contains the client's DH public key. Certificate verify - This message is sent when a client presents a certificate as previously explained. Its purpose is to allow the server to complete the process of authenticating the client. When this message is used, the client sends information that it digitally signs using a cryptographic hash function. When the server decrypts this information with the client's public key, the server is able to authenticate the client. Change cipher spec - The client sends a message telling the server to change to encrypted mode. Finished - The client tells the server that it is ready for secure data communication to begin. Change cipher spec - The server sends a message telling the client to change to encrypted mode. Finished - The server tells the client that it is ready for secure data communication to begin. This is the end of the SSL handshake. Encrypted data - The client and the server communicate using the symmetric encryption algorithm and the cryptographic hash function negotiated in messages 1 and 2, and using the secret key that the client sent to the server in Message 8. The handshake can be renegotiated at this time. See the next section for details. Close Messages - At the end of the connection, each side will send a
If the parameters generated during an SSL session are saved, these parameters can sometimes be reused for future SSL sessions. Saving SSL session parameters allows encrypted communication to begin much more quickly.
現在のwebアプリケーションの多くはhttpsに移行しており、javaを利用してhttpsリクエストを送信する必要がある場合がありますが、サーバには証明書があり、サーバ証明書を得る方法がありません.一般的にjsseの信頼マネージャをカスタマイズして、クライアントがサーバの証明書の有効性を検証しないようにします.この方法は一般的に証明書を迂回するなどと呼ばれています.以下、参考demoをあげます.
Generating and Processing SSL/TLS data
The two main SSLEngine methods wrap() and unwrap() are responsible for generating and consuming network data respectively.
PKIX TrustManager Support
The default trust manager algorithm is "PKIX". The default can be changed by editing the
1.クライアントサーバ交渉で利用可能な暗号化スイート:
クライアントとサーバが開始したSSLセッションで、クライアントは、サーバがサポートしている暗号化スイートのリストを通知するメッセージを送信します.
SSLSocket.getSupportedCipherSuites()を選択し、サーバがより良い暗号化スイートを選択します.
2、Authenticating the Server(認証サーバー)
このステップは、実質的にクライアント認証サーバ、すなわち、クライアントがコミュニケーション中のサーバを信頼するかどうかを選択するかどうかであり、実際にはオプションである.
サーバは自分が主張するアイデンティティであることを証明するために,クライアントに自分の「public key certificate」を提示する必要がある.
公開鍵証明書は、証明書が有効であれば、クライアントがサーバのアイデンティティを確認することができます.
サーバはクライアントと情報を交換し、双方がRSAなどのsecret keyに同意するようにし、クライアントはサーバが提示した証明書からpublic keyを取得し、secret key informationを暗号化し、次に暗号化された情報をサーバに送信し、サーバは自分のprivate keyを利用して情報を復号し、クライアントを認証する.
3、Sending the Encrypted Data
Both the client and the server now have access to the same secret key. With each message, they use the cryptographic hash function, chosen in the first step of this process, and shared secret information, to compute an HMAC that they append to the message. They then use the secret key and the secret key algorithm negotiated in the first step of this process to encrypt the secure data and the HMAC. The client and server can now communicate securely using their encrypted and hashed data.
以下はsslメッセージの図です.
The SSL messages are sent in the following order:
close_notify message
to inform the peer that the connection is closed. If the parameters generated during an SSL session are saved, these parameters can sometimes be reused for future SSL sessions. Saving SSL session parameters allows encrypted communication to begin much more quickly.
import javax.net.ssl.*;
import java.security.*;
// Create/initialize the SSLContext with key material
char[] passphrase = "passphrase".toCharArray();
// First initialize the key and trust material.
KeyStore ksKeys = KeyStore.getInstance("JKS");
ksKeys.load(new FileInputStream("testKeys"), passphrase);
KeyStore ksTrust = KeyStore.getInstance("JKS");
ksTrust.load(new FileInputStream("testTrust"), passphrase);
// KeyManager's decide which key material to use.
KeyManagerFactory kmf =
KeyManagerFactory.getInstance("SunX509");
kmf.init(ksKeys, passphrase);
// TrustManager's decide whether to allow connections.
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("SunX509");
tmf.init(ksTrust);
sslContext = SSLContext.getInstance("TLS");
sslContext.init(
kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// We're ready for the engine.
SSLEngine engine = sslContext.createSSLengine(hostname, port);
// Use as client
engine.setUseClientMode(true);
現在のwebアプリケーションの多くはhttpsに移行しており、javaを利用してhttpsリクエストを送信する必要がある場合がありますが、サーバには証明書があり、サーバ証明書を得る方法がありません.一般的にjsseの信頼マネージャをカスタマイズして、クライアントがサーバの証明書の有効性を検証しないようにします.この方法は一般的に証明書を迂回するなどと呼ばれています.以下、参考demoをあげます.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* @Title: SSLDemo1.java
* @Package
* @Description: TODO( )
* @author huhu
* @date 2016 1 21 10:08:45
* @version V1.0
*/
public class SSLDemo1 {
public static void main(String[] args) throws Exception {
trustAllHttpsCertificates();
HostnameVerifier hv = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
System.out.println("Warning: URL Host: " + hostname + " vs. " + session.getPeerHost());
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
// Https , http
URL url = new URL("https://dynamic.12306.cn/otsweb/main.jsp");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
SSLContext sc = SSLContext.getInstance("SSL");
conn.connect();
// BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())) ;
// String input = "" ;
//
// while((input = br.readLine()) != null){
// System.out.println(input);
// }
}
private static void trustAllHttpsCertificates() throws Exception{
TrustManager[] tms = new TrustManager[1];
TrustManager tm = new CustomTrustManager();
tms[0] = tm ;
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, tms, null);
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
}
static class CustomTrustManager implements X509TrustManager{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
Generating and Processing SSL/TLS data
The two main SSLEngine methods wrap() and unwrap() are responsible for generating and consuming network data respectively.
PKIX TrustManager Support
The default trust manager algorithm is "PKIX". The default can be changed by editing the
ssl.TrustManagerFactory.algorithm
property in the java.security
file. HostnameVerifier
public class MyHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
// pop up an interactive dialog box
// or insert additional matching logic
if (good_address) {
return true;
} else {
return false;
}
}
}
HttpsURLConnection urlc = (HttpsURLConnection)
(new URL("https://www.sun.com/")).openConnection();
urlc.setHostnameVerifier(new MyHostnameVerifier());