Android 加密傳輸(SSL),雙向認證 筆記
工作需要使用到 Android 加密傳輸(SSL),雙向認證 ,因為未使用過,所以搜尋了總結了一下相關知識,並整理作為筆記
參考部落格 :Retrofit 2.0 詳解(二)載入https請求(轉)
搜尋的時候關於SSL+http 的解釋有很多,不做細說,本文只記錄如何實現,包括證書製作、myeclipse服務部署以及Android端程式碼。
證書製作
開啟cmd命令視窗
1、生成客戶端keystore
keytool -genkeypair -alias E:\sslhttpTest\keystool\client -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore E:\sslhttpTest\keystool\client.jks
注:此處 E:\sslhttpTest\keystool\client 是本人手誤 只需輸入 client 即可,alias 無需路徑
2、生成服務端keystore
keytool -genkeypair -alias server -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore E:\sslhttpTest\keystool\server.keystore
3、匯出客戶端證書
keytool -export -alias E:\sslhttpTest\keystool\client -file E:\sslhttpTest\keystool\client.cer -keystore E:\sslhttpTest\keystool\client.jks -storepass 123456
4、匯出服務端證書
keytool -export -alias server -file E:\sslhttpTest\keystool\server.cer -keystore E:\sslhttpTest\keystool\server.keystore -storepass 123456
5、重點:證書交換
將客戶端證書匯入服務端keystore中,再將服務端證書匯入客戶端keystore中, 一個keystore可以匯入多個證書,生成證書列表。
生成客戶端信任證書庫(由服務端證書生成的證書庫):
keytool -import -v -alias server -file E:\sslhttpTest\keystool\server.cer -keystore E:\sslhttpTest\keystool\truststore_s_for_c.jks -storepass 123456
將客戶端證書匯入到伺服器證書庫(使得伺服器信任客戶端證書):
keytool -import -v -alias E:\sslhttpTest\keystool\client -file E:\sslhttpTest\keystool\client.cer -keystore E:\sslhttpTest\keystool\client_for_server.keystore -storepass 123456
6、生成Android識別的BKS庫檔案
下載地址: protecle.jar 百度網盤下載地址
執行protecle.jar將client.jks和truststore_s_for_c.jks分別轉換成client.bks和truststore_s_for_c.bks ,然後放到android客戶端的assert目錄下
File -> open Keystore File -> 選擇證書庫檔案 -> 輸入密碼 -> Tools -> change keystore type -> BKS -> save keystore as -> 儲存即可
7、配置Tomcat伺服器(可選)
找到Tomcat安裝目錄 conf\server.xml檔案,配置8443埠
<Connector
SSLEnabled="true"
acceptCount="100"
clientAuth="true"
disableUploadTimeout="true"
enableLookups="true"
keystoreFile="E:/sslhttpTest/keystool/server.keystore"
keystorePass="123456"
maxSpareThreads="75"
maxThreads="200"
minSpareThreads="5"
port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
sslProtocol="TLS"
truststoreFile="E:/sslhttpTest/keystool/client_for_server.keystore"
truststorePass="123456"/>
注:
可以不配置tomcat ,只需配置 eclipse 的工程目錄中的對應的server.xml檔案 E:\eclipsework\.metadata\.me_tcat7\conf\server.xml(我的工程目錄在E:\eclipsework 根據實際情況找路徑) 。如果 eclipsework\.metadata\.me_tcat7 的目錄下沒有 conf 目錄,需要新建conf資料夾然後將 tomcat 安裝目錄 conf\server.xml檔案複製過來,然後啟動myeclipse的服務,會報錯 根據報錯刪除
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
即可,配置 server.xml 的埠
<Connector
SSLEnabled="true"
acceptCount="100"
clientAuth="true"
disableUploadTimeout="true"
enableLookups="true"
keystoreFile="E:/sslhttpTest/keystool/server.keystore"
keystorePass="123456"
maxSpareThreads="75"
maxThreads="200"
minSpareThreads="5"
port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
sslProtocol="TLS"
truststoreFile="E:/sslhttpTest/keystool/client_for_server.keystore"
truststorePass="123456"/>
Android 端配置
SSLHelper
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
public class SSLHelper {
private static final String TAG = "SSLHelper";
private final static String CLIENT_PRI_KEY = "client";
private final static String TRUSTSTORE_PUB_KEY = "truststore_s_for_c";
private final static String CLIENT_BKS_PASSWORD = "123456";
private final static String TRUSTSTORE_BKS_PASSWORD = "123456";
private final static String KEYSTORE_TYPE = "BKS";
private final static String PROTOCOL_TYPE = "TLS";
private final static String CERTIFICATE_FORMAT = "X509";
public static SSLSocketFactory getSSLCertifcation(Context context) {
SSLSocketFactory sslSocketFactory = null;
try { // 伺服器端需要驗證的客戶端證書,其實就是客戶端的keystore
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);// 客戶端信任的伺服器端證書
KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE);//讀取證書
InputStream ksIn = context.getAssets().open(CLIENT_PRI_KEY);
InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);//載入證書
keyStore.load(ksIn, CLIENT_BKS_PASSWORD.toCharArray());
trustStore.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
ksIn.close();
tsIn.close(); //初始化
SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_FORMAT);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_FORMAT);
trustManagerFactory.init(trustStore);
keyManagerFactory.init(keyStore, CLIENT_BKS_PASSWORD.toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
sslSocketFactory = sslContext.getSocketFactory();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslSocketFactory;
}
}
UnSafeTrustManager
public class UnSafeTrustManager 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 new X509Certificate[]{};
}
}
Retrofit 初始化
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//建立okhttp
OkHttpClient httpClient = new OkHttpClient().newBuilder()
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.connectTimeout(30, TimeUnit.SECONDS)
.sslSocketFactory(SSLHelper.getSSLCertifcation(context), new UnSafeTrustManager())
.hostnameVerifier(new HttpsUtil.UnSafeHostnameVerifier())//由於還沒有域名,此處設定忽略掉域名校驗
.build();
retrofit=new Retrofit.Builder()
.baseUrl(url)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
所有程式碼可以在百度網盤下載
百度網盤連結:測試程式下載
密碼:on6o
目錄說明:keystool.zip 測試證書壓縮包
LoginSSL.zip 測試後臺壓縮包
SSLTest.zip 測試Android 壓縮包 ,使用時請替換 MainActivity中的 url 地址的 ip 修改為測試的IP地址