您的位置:首页 > 移动开发 > Android开发

Android客户端的SSLSocket通信实例源码(PC做服务器、BKS密库)

2017-06-12 22:28 253 查看
>基本知识

  SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。  

  而默认情况下,java利用的是TLS和JKS密库。建议先看一下下方这篇PC-PC间SSLsocket通信的实例。

  本文最终实例见文末。

>PC与PC间的SSL Socket通信

技术实现详见:http://blog.csdn.net/shenpibaipao/article/details/72984015

Attr:JKS密库,无证书自签名验证。

>安卓与PC间的SSL Socket通信

Attr:BKS密库,要求进行证书自签名验证

>“PC-PC”与“安卓-PC”这两种模式在实现上有何不同?

1.PC上必须使用JKS密库,安卓上必须使用BKS密库。

2.安卓对所有自签名证书都要求自检,否则可能会抛出下面这个异常:Trust anchor for certification path not found.

3.安卓的网络操作必须放在非主线程中:详见:http://blog.csdn.net/shenpibaipao/article/details/70304702

>如何构建BKS密库

Java自带的keytool并没有自带BKS密库,因此需要到Bouncy Castle的官网去下载对应JDK的包:

http://www.bouncycastle.org/latest_releases.html

1.5-1.8的包可以到这里下载:

http://download.csdn.net/detail/shenpibaipao/9868576

环境的搭建:

1. 把bcprov-xxxxx.jar放到jdk1.x.xx\jre\lib\ext目录下

2. 在jdk1.x.xx\jre\lib\security目录中的java.security文件里增加一行提供者信息:

security.provider.X=org.bouncycastle.jce.provider.BouncyCastleProvider
其中,X为优先级数字,顺着原来的数字往下,如图:



接着,启动keytool(详见PC-PC中的那一篇),利用-storetype BKS指令构建BKS密库。

>构建秘钥库和Trust秘钥库的样例指令:

//1.服务端密库(默认为JKS密库,也就是PC要用的密库)
keytool -genkey -keystore ./server.ks -storepass server -keyalg RSA -keypass server
//2.客户端密库 注意提供者信息和BKS
keytool -genkey -keystore ./client.ks -storepass client -keyalg RSA -keypass client -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
//3.服务器导出证书server.crt
keytool -exportcert -keystore ./server.ks -storepass server -file ./server.crt
//4.客户端导出证书client.crt 注意提供提供者的信息和导出为BKS
keytool -exportcert -keystore ./client.ks -storepass client -storetype BKS -file ./client.crt -provider org.bouncycastle.jce.provider.BouncyCastleProvider
//5.把客户端证书导入到信任库中,该信任库由客户端持有。详见“PC-PC”那篇文章里的逻辑图
keytool -import -keystore ./tserver.bks -storetype BKS -storepass client -file ./server.crt
//6.~略
keytool -import -keystore ./tclient.jks -storetype JKS -storepass server -file ./client.crt


逻辑图建议参考“PC-PC”里的那个,便于理解。

再强调一遍,安卓端的密库必须是BKS,PC端的密库必须是JKS,否者会在握手阶段抛出异常。

>客户端自验证自签名证书

详见:http://blog.csdn.net/u013424496/article/details/51161647

可以先跳过,遇到异常再回来看看。(其实就是重写相关方法,把安卓强制验证写空了而已)

>实例代码:

服务端代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;

public class ServerSSLTest {

static String keystorePath = "你的路径/server.ks";
static String trustKeystorePath = "你的路径/tclient.jks";
static String keystorePassword = "server";
public static void main(String args[]) throws Exception{
//System.setProperty("javax.net.debug", "ssl,handshake");
System.setProperty("javax.net.ssl.keyStore", keystorePath);
System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);
System.setProperty("javax.net.ssl.trustStore", trustKeystorePath);
System.setProperty("javax.net.ssl.trustStorePassword",keystorePassword);

ServerSocketFactory factory =  SSLServerSocketFactory.getDefault();
SSLServerSocket serverSocket=(SSLServerSocket) factory.createServerSocket(9100);
serverSocket.setNeedClientAuth(false);
System.out.println("Server Open");
Socket socket =serverSocket.accept();
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
System.out.println("Server Log:"+in.readLine());
}
}

客户端代码:

public void initssl() {
try {
//取得SSL的SSLContext实例
SSLContext sslContext = SSLContext.getInstance("TLS");
//取得KeyManagerFactory和TrustManagerFactory的X509密钥管理器实例
KeyManagerFactory keyManager = KeyManagerFactory.getInstance("X509");
TrustManagerFactory trustManager = TrustManagerFactory.getInstance("X509");
//取得BKS密库实例
KeyStore ks= KeyStore.getInstance("BKS");
KeyStore tks = KeyStore.getInstance("BKS");
//加客户端载证书和私钥,通过读取资源文件的方式读取密钥和信任证书
ks.load(getBaseContext()
.getResources()
.openRawResource(R.raw.client),"client".toCharArray());//从raw中获取秘钥库
tks.load(getBaseContext()
.getResources()
.openRawResource(R.raw.tserver),"client".toCharArray());//从raw中获取信任库
//初始化密钥管理器
keyManager.init(ks,"client".toCharArray());
trustManager.init(tks);
//初始化SSLContext
sslContext.init(keyManager.getKeyManagers(),trustManager.getTrustManagers(),null);
//获取SSLSocket
sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket("192.168.1.103",9100);
} catch (Exception e) {
e.printStackTrace();
}
}
private SSLSocket sslSocket;
Runnable runnable=new Runnable() {
@Override
public void run() {
/*
会抛出信任库异常,不能这么写
System.setProperty("javax.net.ssl.keyStore", keystorePath);
System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);
System.setProperty("javax.net.ssl.trustStore", trustKeystorePath);
System.setProperty("javax.net.ssl.trustStorePassword",keystorePassword);
*/
try{
initssl();
System.out.println("Client Connected");
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(sslSocket.getOutputStream(),"UTF-8"));
System.out.println("Msg ready");
out.write("This is message:你好"+"\n");
out.flush();
System.out.println("Msg Sended");
}catch (Exception e){
e.printStackTrace();
}

}
};
其中,client.ks和tserver.jks(这里是我命名失误,这两个都是BKS的库,可参见上面那六行命令,打的是bks)放于安卓工程里res/raw文件夹里(如果没有就自己创建一个),如图:



如果想把证书导出到sdcard中做其他操作,见此:http://blog.csdn.net/shenpibaipao/article/details/73032148

服务端输出结果:



>其他参考文章:

http://blog.sina.com.cn/s/blog_792cc4290100syyf.html

http://kb.cnblogs.com/page/162080/

http://www.cnblogs.com/zhujiabin/p/5895079.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ssl android pc 实例 通信