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

来源:互联网 发布:淘宝怎么出租游戏账号 编辑:程序博客网 时间:2024/05/11 21:24

>基本知识

  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.客户端密库 注意提供者信息和BKSkeytool -genkey -keystore ./client.ks -storepass client -keyalg RSA -keypass client -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider//3.服务器导出证书server.crtkeytool -exportcert -keystore ./server.ks -storepass server -file ./server.crt//4.客户端导出证书client.crt 注意提供提供者的信息和导出为BKSkeytool -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

阅读全文
1 0