一、自签名密钥和证书

1、生成服务端密钥

2、生成服务端证书

3、生成客户端密钥

4、生成客户端证书

5、将server端证书添加到serverTrust_ks.jks文件中

6、将client端证书添加到clientTrust_ks.jks文件中

(以上生成过程详见:https://blog.csdn.net/weixin_43192102/article/details/122214603)

7、将jks密钥转换为bks格式密钥(因为Android只支持.bks格式的密钥文件)

(转换工具详见:jks文件转bks文件.zip-Java文档类资源-CSDN下载)

8、服务端代码

package com.ssl.socket.server;import android.os.Bundle;
import android.view.View;
import android.widget.Button;import androidx.appcompat.app.AppCompatActivity;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManagerFactory;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnServer = findViewById(R.id.btn_server);btnServer.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {new Thread(new ServerOne()).start();}});}public static class ServerOne implements Runnable {//SSL协议版本private static final String TLS = "TLSv1.2";//KeyStore的类型private static final String PROVIDER = "X509";//秘钥类型,java默认是JKS,Android不支持JKS,只能用BKS
//        private static final String STORE_TYPE = "JKS";private static final String STORE_TYPE = "BKS";//秘钥的路径private static final String KEY_STORE_NAME = "server_ks.bks";private static final String TRUST_STORE_NAME = "clientTrust_ks.bks";//Server的端口private static final int DEFAULT_PORT = 8090; //自定义端口//秘钥的密码private static final String SERVER_KEY_STORE_PASSWORD = "server_password"; //秘钥的密码private static final String SERVER_TRUST_KEY_STORE_PASSWORD = "server";//密码@Overridepublic void run() {SSLServerSocket sslServerSocket = null;try {//获取SSLContextSSLContext sslContext = SSLContext.getInstance(TLS);//生成秘钥的managerKeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);//加载信任的证书TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);//加载秘钥KeyStore keyStoreOne = KeyStore.getInstance(STORE_TYPE);KeyStore keyStoreTwo = KeyStore.getInstance(STORE_TYPE);keyStoreOne.load(MyApplication.getContext().getAssets().open(KEY_STORE_NAME), SERVER_KEY_STORE_PASSWORD.toCharArray());keyStoreTwo.load(MyApplication.getContext().getAssets().open(TRUST_STORE_NAME), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());//秘钥初始化keyManagerFactory.init(keyStoreOne, SERVER_KEY_STORE_PASSWORD.toCharArray());trustManagerFactory.init(keyStoreTwo);//初始化SSLContextsslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);//获取SSLContext的SocketFactorysslServerSocket = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(DEFAULT_PORT);//是否开启双向验证
//                sslServerSocket.setNeedClientAuth(false);sslServerSocket.setNeedClientAuth(true);System.out.println("服务器已开启,等待连接 .....");while (true) {Socket accept = sslServerSocket.accept();accept.setKeepAlive(true);System.out.println("客户端 : " + accept.getInetAddress().getHostAddress());try (InputStream inputStream = accept.getInputStream();OutputStream outputStream = accept.getOutputStream();) {byteMsgReader(inputStream, outputStream);} catch (Exception e) {System.out.println(e.toString());}}} catch (Exception e) {e.printStackTrace();try {if (sslServerSocket != null) {sslServerSocket.close();System.out.println("服务器关闭!");}} catch (Exception ex) {ex.printStackTrace();}}}}/*** 字节流-解析客户端的消息*/public static void byteMsgReader(InputStream inputStream, OutputStream outputStream) throws Exception {BufferedInputStream bis = new BufferedInputStream(inputStream);byte[] buffer = new byte[20];int length = bis.read(buffer);System.out.println("Receive: " + new String(buffer, 0, length));System.out.println("接收完成第一个文件");byteMsgWriter(outputStream);bis = new BufferedInputStream(inputStream);buffer = new byte[20];length = bis.read(buffer);System.out.println("Receive: " + new String(buffer, 0, length));System.out.println("接收完成第二个文件");byteMsgWriter(outputStream);}/*** 字节流-发送给客户端回执消息*/public static void byteMsgWriter(OutputStream outputStream) throws Exception {BufferedOutputStream bufferedOutputStreamBack = new BufferedOutputStream(outputStream);bufferedOutputStreamBack.write("服务端已成功接收文件.".getBytes(StandardCharsets.UTF_8));bufferedOutputStreamBack.write("\n".getBytes(StandardCharsets.UTF_8));bufferedOutputStreamBack.flush();                // 第一次发送消息,长连接实现方式}}

9、客户端代码

package com.ssl.socket.client;import android.os.Bundle;
import android.view.View;
import android.widget.Button;import androidx.appcompat.app.AppCompatActivity;import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnClient = findViewById(R.id.btn_client);btnClient.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}new Thread(new ClientOne()).start();}});}public static class ClientOne implements Runnable {private static final String TLS = "TLSv1.2";private static final String PROVIDER = "X509";private static final String STORE_TYPE = "BKS";private static final String TRUST_STORE_NAME = "serverTrust_ks.bks";private static final String KEY_STORE_NAME = "client_ks.bks";private static final String CLIENT_KEY_STORE_PASSWORD = "client_password"; //密码private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "client";//密码@Overridepublic void run() {SSLSocket socket = null;try {SSLContext sslContext = SSLContext.getInstance(TLS);KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);//生成信任证书Manager,默认系统会信任CA机构颁发的证书,自定的证书需要手动的加载TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);KeyStore keyStoreOne = KeyStore.getInstance(STORE_TYPE);KeyStore keyStoreTwo = KeyStore.getInstance(STORE_TYPE);//加载client端密钥keyStoreOne.load(MyApplication.getContext().getAssets().open(KEY_STORE_NAME), CLIENT_KEY_STORE_PASSWORD.toCharArray());//信任证书keyStoreTwo.load(MyApplication.getContext().getAssets().open(TRUST_STORE_NAME), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());keyManagerFactory.init(keyStoreOne, CLIENT_KEY_STORE_PASSWORD.toCharArray());trustManagerFactory.init(keyStoreTwo);//初始化sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);socket = (SSLSocket) sslContext.getSocketFactory().createSocket("localhost", 8090);
//                socket.startHandshake();socket.setKeepAlive(true);
//                socket.setSoTimeout(10000);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream();) {byteMsgWriter(outputStream, inputStream);} catch (Exception ex) {ex.printStackTrace();}} catch (Exception e) {e.printStackTrace();try {if (socket != null) {socket.close();System.out.println("客户端关闭");}} catch (Exception ex) {ex.printStackTrace();}}}}/*** 字节流-发送给服务端*/public static void byteMsgWriter(OutputStream outputStream, InputStream inputStream) throws Exception {BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);bufferedOutputStream.write("Hello".getBytes());bufferedOutputStream.flush();                     // 第一次发送消息,长连接实现方式Thread.sleep(1);                                // 必须加休眠,否则第二个文件流会发生错乱characterMsgReader(inputStream);                    // 从服务端接收消息bufferedOutputStream.write("World".getBytes());bufferedOutputStream.flush();                    // 第二次发送消息,长连接实现方式characterMsgReader(inputStream);                    // 从服务端接收消息}/*** 字符流-解析服务端的回执消息-不间断解析*/public static void characterMsgReader(InputStream inputStream) throws Exception {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = bufferedReader.readLine()) != null) {System.out.println("服务端消息: " + line);}}}

二、CA签发密钥和证书

1、将CA server端证书添加到serverTrust_ks.jks文件中

命令:keytool -import -keystore serverTrust_ks.jks -storepass client -file server.crt

结果:会生成serverTrust_ks.jks密钥文件

操作:将生成的serverTrust_ks.jks密钥文件配置到客户端

2、将CA签发密钥转换为pfx格式密钥

命令:openssl pkcs12 -export -inkey client.key -in client.crt -out client.pfx

结果:会生成client.pfx证书文件

(注:如果没有OpenSSL命令则先下载OpenSSL包)

3、将pfx格式文件转换为Android支持的bks格式文件

(转换工具详见:jks文件转bks文件.zip-Java文档类资源-CSDN下载)

操作:将生成的client_ks.bks密钥文件配置到客户端

4、客户端完整代码(代码中的业务根据具体需求进行修改)

    private static Thread thread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnClient = findViewById(R.id.btn_client);btnClient.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {thread = new Thread(new ClientOne());thread.start();}});}public static class ClientOne implements Runnable {private static final String TLS = "TLS";private static final String PROVIDER = "X509";private static final String STORE_TYPE = "BKS";private static final String TRUST_STORE_NAME = "serverTrust_ks.bks";private static final String KEY_STORE_NAME = "client_ks.bks";private static final String CLIENT_KEY_STORE_PASSWORD = "screen"; //密码private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "client";//密码private static final int PORT = 28007;@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overridepublic void run() {SSLSocket socket = null;try {SSLContext sslContext = SSLContext.getInstance(TLS);KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);//生成信任证书Manager,默认系统会信任CA机构颁发的证书,自定的证书需要手动的加载TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);KeyStore keyStoreOne = KeyStore.getInstance(STORE_TYPE);KeyStore keyStoreTwo = KeyStore.getInstance(STORE_TYPE);//加载client端密钥keyStoreOne.load(MyApplication.getContext().getAssets().open(KEY_STORE_NAME), CLIENT_KEY_STORE_PASSWORD.toCharArray());//信任证书keyStoreTwo.load(MyApplication.getContext().getAssets().open(TRUST_STORE_NAME), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());keyManagerFactory.init(keyStoreOne, CLIENT_KEY_STORE_PASSWORD.toCharArray());trustManagerFactory.init(keyStoreTwo);//初始化sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);socket = (SSLSocket) sslContext.getSocketFactory().createSocket(HOST, PORT);
//                socket.startHandshake();socket.setKeepAlive(true);
//                socket.setSoTimeout(10000);//不关闭连接(长连接)while (true) {InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream();byteMsgWriter(outputStream, inputStream);}} catch (Exception e) {e.printStackTrace();try {if (socket != null) {socket.close();System.out.println("客户端关闭");IS_OK = true;}if (!thread.isInterrupted()) {thread.interrupt();}} catch (Exception ex) {ex.printStackTrace();}}}}/*** 字节流-发送给服务端*/public static void byteMsgWriter(OutputStream outputStream, InputStream inputStream) throws Exception {BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);if (IS_OK) {bufferedOutputStream.write(HexUtil.decodeHex("03000201000000004F4B"));bufferedOutputStream.flush();                     // 第一次发送消息,长连接实现方式IS_OK = false;Thread.sleep(10);                                // 必须加休眠,否则第二个文件流会发生错乱}characterMsgReader(inputStream, bufferedOutputStream);                    // 从服务端接收消息}/*** 字符流-解析服务端的回执消息-不间断解析*/public static void characterMsgReader(InputStream inputStream, BufferedOutputStream bufferedOutputStream) throws Exception {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));char[] chars = new char[8];bufferedReader.read(chars, 0, chars.length);//得到8位请求头的数据包String packet = HexUtil.encodeHexStr(String.valueOf(chars));//解析得到命令码String commandCode = packet.substring(0, 2);//得到数据长度int dataLen = Integer.parseInt(packet.substring(2, 6), 16);switch (commandCode) {case "00"://心跳检测Log.e("MainActivity", "心跳检测");bufferedOutputStream.write("Yes".getBytes(StandardCharsets.UTF_8));bufferedOutputStream.flush();                     // 第一次发送消息,长连接实现方式
//                Thread.sleep(10);                                // 必须加休眠,否则第二个文件流会发生错乱break;case "01"://业务System.out.println("业务操作");break;case "02"://断开连接System.out.println("断开连接");break;case "03"://确认授权System.out.println("确认授权");break;case "F1"://WIFISystem.out.println("WIFI");break;case "F2"://蓝牙System.out.println("蓝牙");break;}}

Android实现SSL Socket双向认证相关推荐

  1. java使用bks双向认证_android客户端SSL单向双向认证

    最近一直在做SSL的研究,前几天写了一篇SSL握手过程的文章,今天写下android客户端SSL单双向认证的示例 操作系统是win7,服务器用的tomcat6,客户端跑在1.6的模拟器上,证书都是自签 ...

  2. SSL/TSL双向认证过程与Wireshark抓包分析

    原博文 1. SSL/TSL基本知识 (1)SSL/TLS协议运行机制:https://blog.csdn.net/fw0124/article/details/40873253 (2)图解SSL/T ...

  3. SSL/TLS 双向认证(一) -- SSL/TLS工作原理

    本文部分参考: https://www.wosign.com/faq/faq2016-0309-03.htm https://www.wosign.com/faq/faq2016-0309-04.ht ...

  4. SSL/TLS 双向认证(一) -- SSL/TLS 工作原理

    本文部分参考: https://www.wosign.com/faq/faq2016-0309-03.htm https://www.wosign.com/faq/faq2016-0309-04.ht ...

  5. SSL/TLS 双向认证

    其他参考链接 链接: https://blog.csdn.net/xxss120/article/details/78758832. 链接: https://blog.csdn.net/gx_1983 ...

  6. 详解Nginx SSL快速双向认证配置(脚本)

    这篇文章主要介绍了详解Nginx SSL快速双向认证配置(脚本),现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 目前遇到一个项目有安全性要求,要求只有个别用户有权限访问.本着能用配置解决就 ...

  7. SSL Tomcat 双向认证

    基本逻辑: 1.生成服务端密钥库并导出证书: 2.生成客户端密钥库并导出证书: 3.根据服务端密钥库生成客户端信任的证书: 4.将客户端证书导入服务端密钥库: 5.将服务端证书导入浏览器. 基本思路解 ...

  8. GCDAsyncSOcket使用及其SSL/TLS双向认证的实现

    GCDAsyncSoceket使用及其SSL/TLS的实现 关于GCDAsyncSocket:首先我们得知道GCDAsnyc是由第三方开发的一个苹果系统的socket库,功能强大,而且简单易用.当然关 ...

  9. php双向验证SSL,https双向认证如何开启

    一.Http HyperText Transfer Protocol,超文本传输协议,是互联网上使用最广泛的一种协议,所有WWW文件必须遵循的标准.HTTP协议传输的数据都是未加密的,也就是明文的,因 ...

  10. Android应用实现Https双向认证

    为什么需要双向认证 Https保证的是信道的安全,即客户端和服务端通信报文的安全.但是无法保证中间人攻击,所以双向认证解决的问题就是防止中间人攻击. 中间人攻击(Man-in-the-MiddleAt ...

最新文章

  1. 一行代码不用写,就可以训练、测试、使用模型,这个star量1.5k的项目帮你做到...
  2. C\C++对文件的读写操作
  3. Android关于Handler发送消息里面的arg1和arg2以及obj和what的用法
  4. 把握数据库发展趋势 DBA应如何避免“踩坑”?
  5. scala特性_Scala | 特性应用
  6. 开发基于深度学习的人脸识别【考勤/签到】系统
  7. 凝结芽孢杆菌行业调研报告 - 市场现状分析与发展前景预测
  8. pcDuino–voip服务器设置呼叫彩铃
  9. 从零开始学ios开发(十四):Navigation Controllers and Table Views(上)
  10. POJ3262 Protecting the Flowers【贪心】
  11. QQ音乐文件缓存位置以及修改方法步骤
  12. BUUCTF[SCTF2019]Who is he题解
  13. MCAL PWM Module详解
  14. DIY移动端网易云音乐
  15. golang项目持续集成Travis-CI实践
  16. 菜鸟也能飞:SQL数据库实战专业教程(二)
  17. QueryRunner中query方法
  18. 服务器上部署前端Vue项目代码
  19. 西门子HMI精智面板密码超期功能
  20. 用python将excel表格中b列列名改为c

热门文章

  1. 戳这里,誉天胡老师教你如何备考 HCIE-Datacom!考试通关so easy!
  2. javascript英语单词音节拆分_英语单词音节的划分法
  3. matlab小苹果,我要用计算器弹曲子,求亲们发点计算器简谱
  4. 内存泄露的检测工具——Valgrind
  5. C++ 复数计算器 简单代码
  6. “匠心之韵,数据之美”之InfoQ专访COO叶谦:解读全域大数据战略背后的技术演进...
  7. Druid——Hadoop-based Batch Ingestion
  8. jenkins配置svn提交一键自动部署
  9. TensorFlow学习笔记(4)——TensorFlow实现GloVe
  10. CreateFile函数详解 不仅仅是对文件的操作 还有对系统设备的IO的操作