今天从 这位大神 这学到了,权当记录一下了。
简单来说,HTTPS就是“安全版”的HTTP, HTTPS = 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)。
基于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,就到这里,如有疑问,咱们可以相互讨论,共同进步。