Android 加密传输(SSL),双向认证 笔记

工作需要使用到 Android  加密传输(SSL),双向认证 ,因为未使用过,所以搜索了总结了一下相关知识,并整理作为笔记

参考博客 :Retrofit 2.0 详解(二)加载https请求(转)

                   Android实现ssl双向验证

搜索的时候关于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

扫描二维码关注公众号,回复: 4488364 查看本文章

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.jkstruststore_s_for_c.jks分别转换成client.bkstruststore_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地址

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_41191134/article/details/83182374