Android HTTPS 双向认证(基于OkHttp + Retrofit + Rxjava)

 今天从 这位大神 这学到了,权当记录一下了。

先介绍下HTTPS吧

简单来说,HTTPS就是“安全版”HTTPHTTPS = HTTP + SSL。HTTPS相当于在应用层和TCP层之间加入了一个SSL(或TLS),SSL层对从应用层收到的数据进行加密。TLS/SSL中使用了RSA非对称加密,对称加密以及HASH算法

RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥

 

SSL:(Secure Socket Layer,安全套接字层),为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。
SSL协议可分为两层:
SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。TLS 1.0是IETF(Internet Engineering Task Force,Internet工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本,可以理解为SSL 3.1,它是写入了 RFC的。
该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)

Android HTTPS 双向认证(基于OkHttp + Retrofit + Rxjava)_第1张图片

进入正文

基于Retrofit实现HTTPS思路

OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .sslSocketFactory(SSLManager.getSSLCertifcation(context))//为OkHttp对象设置SocketFactory用于双向认证
    .hostnameVerifier(new UnSafeHostnameVerifier())
    .build();
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://10.2.8.56:8443")
    .addConverterFactory(GsonConverterFactory.create())//添加 json 转换器
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器
    .client(okHttpClient)//添加OkHttp代理对象
    .build();

  首先对于双向证书验证,也就是说,客户端持有服务端的公钥证书,并持有自己的私钥服务端持有客户的公钥证书,并持有自己私钥。
1.建立连接的时候,客户端利用服务端的公钥证书来验证服务器是否上是目标服务器;服务端利用客户端的公钥来验证客户端是否是目标客户端。
2.服务端给客户端发送数据时,需要将服务端的证书发给客户端验证,验证通过才运行发送数据,同样,客户端请求服务器数据时,也需要将自己的证书发给服务端验证,通过才允许执行请求。

好了,开始制作证书:

1.生成APP客户端jks证书(打开android studio 的terminal,输入以下命令)

keytool -genkeypair -alias client -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore local.jks

之后你会在项目的根目录下发现生成了local.jks证书 

2.生成服务端keystore证书(打开android studio 的terminal,输入一下命令))

keytool -genkeypair -alias server -keyalg RSA -validity 3650 -keypass 123456 -storepass 123456 -keystore server.keystore

 之后你会在项目的根目录下发现生成了server.keystore证书 

3.导出客户端证书(将local.jks导出成为local.cer)

keytool -export -alias client -file local.cer -keystore local.jks -storepass 123456 

之后你会在项目的根目录下发现生成了local.cer证书  

4.导出服务端证书(将lserver.keystore导出成为server.cer)

keytool -export -alias server -file server.cer -keystore server.keystore -storepass 123456 

之后你会在项目的根目录下发现生成了server.cer证书   

到这里位置,项目根目录下一家有四个证书文件了,local.jks   local.cer  server.keystore  server.cer ,都有什么用呢,别着急,马上说到;

5.证书融合

(1)生成客户端信任证书库

keytool -import -v -alias server -file server.cer -keystore truststorelist.jks -storepass 123456

之后你会在项目的根目录下发现生成了truststorelist.jks证书 ,这个就是客户端信任证书库

(2)将客户端证书导入到服务器证书库(使得服务器信任客户端证书):

    keytool -import -v -alias client -file local.cer -keystore server.keystore -storepass 123456 

(3)将Android是被不了的jks文件转换成能是被的BKS文件

Portecle(下载地址)工具转成bks格式,最新版本是1.10。
运行protecle.jar将client.jks和truststore.jks分别转换成client.bks和truststore.bks,然后放到android客户端的assert目录下
操作步骤如下: 
>File -> open Keystore File -> 选择证书库文件 -> 输入密码 -> Tools -> change keystore type -> BKS -> save keystore as -> 保存即可

6.服务端配置(tomcat配置)


 

7.SSLSocketFactory自定义,新建SSLManager类 

/**
*Create by wz
* 自定义SSLSocketFactory 读取证书
*/
public class SSLManager{

private final static String LOCAL_PRI_KEY = "local.bks";
private final static String TRUSTSTORE_PUB_KEY = "truststore.bks";
private final static String LOCALT_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(LOCAL_PRI_KEY );
    InputStream tsIn = context.getAssets().open(TRUSTSTORE_PUB_KEY);//加载证书
    keyStore.load(ksIn, LOCAL_BKS_PASSWORD.toCharArray());
    trustStore.load(tsIn, TRUSTSTORE_BKS_PASSWORD.toCharArray());
    ksIn.close();
    tsIn.close();
    //初始化SSLContext
    SSLContext sslContext = SSLContext.getInstance(PROTOCOL_TYPE);
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(CERTIFICATE_FORMAT);
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(CERTIFICATE_FORMAT);
    trustManagerFactory.init(trustStore);
    keyManagerFactory.init(keyStore, LOCAL_BKS_PASSWORD.toCharArray());
    sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); 
 
    sslSocketFactory = sslContext.getSocketFactory();
 
  } catch (KeyStoreException e) {
    //TODO 异常处理
//...
   }
  return sslSocketFactory;
 }
}

 8.OkHttpClient

 

kHttpClient okHttpClient = new OkHttpClient.Builder()
      .sslSocketFactory(SSLManager.getSSLCertifcation(context))//获取SSLSocketFactory
      .hostnameVerifier(new UnSafeHostnameVerifier())//添加hostName验证器
      .build();
 
  Retrofit retrofit = new Retrofit.Builder()
       .baseUrl("https://10.2.8.56:8443")//填写自己服务器IP
       .addConverterFactory(GsonConverterFactory.create())//添加 json 转换器
       .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加 RxJava 适配器
       .client(okHttpClient)
       .build();
 

 

private class UnSafeHostnameVerifier implements HostnameVerifier {
  @Override
  public boolean verify(String hostname, SSLSession session) {
      return true;
  }
}

 OK,就到这里,如有疑问,咱们可以相互讨论,共同进步。


你可能感兴趣的:(Android HTTPS 双向认证(基于OkHttp + Retrofit + Rxjava))