SSL+Socket 初步整理

SSL概念

SSL(Secure Sockets Layer,安全套接层),安全套接层是Netscape公司率先采用的网络安全协议。它是在传输通信协议(TCP/IP)上实现的一种安全协议,采用公开密钥技术。SSL广泛支持各种类型的网络,同时提供三种基本的安全服务,它们都使用公开密钥技术。

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

Socket概念

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

客户端证书生成

服务端给我们一个服务端的.pem格式的证书,通过Java指令将服务端证书添加到我们的密钥库中,生成我们的证书
keytool -import -alias 别名 -file 服务端证书路径 -storetype 密钥库(如 :JKS、BKS) -storepass 密码 -keystore (路径非必需)+ 文件名 -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-1.46.jar(换成自己的jar)

这里的storetype如果是Java服务用JKS,Android用BKS
后边的provider如果不用的话可能会在加载密钥库的时候出错,并且后边用的jar包如果1.46不可以的话可以换换版本试试,比如1.45。

代码实现

  1. 准备好必要的参数
private static final int SERVER_PORT = 0000;//端口号
private static final String SERVER_IP = "00.000.000.00";//连接IP
private static final String CLIENT_KET_PASSWORD = "000000";//私钥密码
private static final String CLIENT_TRUST_PASSWORD = "000000";//信任证书密码
private static final String CLIENT_AGREEMENT = "TLS";//使用协议
private static final String CLIENT_KEY_MANAGER = "X509";//密钥管理器(如果是Java服务此处为SunX509)
private static final String CLIENT_TRUST_MANAGER = "X509";//
private static final String CLIENT_KEY_KEYSTORE = "BKS";//密库,这里用的是BouncyCastle密库(Java服务为JKS)
private static final String CLIENT_TRUST_KEYSTORE = "BKS";//    
  1. 生成SSLSocket对象
public void init(Context context) {
    try {
        //取得KeyManagerFactory和TrustManagerFactory的X509密钥管理器实例
        KeyManagerFactory keyManager = KeyManagerFactory.getInstance(CLIENT_KEY_MANAGER);
        TrustManagerFactory trustManager = TrustManagerFactory.getInstance(CLIENT_TRUST_MANAGER);
        //取得BKS密库实例
        KeyStore kks = KeyStore.getInstance(CLIENT_KEY_KEYSTORE);
        KeyStore tks = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);
        //加客户端载证书和私钥,通过读取资源文件的方式读取密钥和信任证书
        kks.load(context
                .getResources()
                .openRawResource(R.raw.keyclient), CLIENT_KET_PASSWORD.toCharArray());
        tks.load(context
                .getResources()
                .openRawResource(R.raw.keyclient), CLIENT_TRUST_PASSWORD.toCharArray());
        //初始化密钥管理器
        keyManager.init(kks, CLIENT_KET_PASSWORD.toCharArray());
        trustManager.init(tks);

        //取得SSL的SSLContext实例
        SSLContext sslContext = SSLContext.getInstance(CLIENT_AGREEMENT);
        //初始化SSLContext
        sslContext.init(keyManager.getKeyManagers(), trustManager.getTrustManagers(), null);

        //生成SSLSocket
        Client_sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(SERVER_IP, SERVER_PORT);
        Client_sslSocket.setNeedClientAuth(true);
    } catch (Exception e) {
        e.printStackTrace();
    }
} 
  1. 发送数据
public void write(String body){
        try {
            byte data[] = dataProcessing(body);
            if (data == null || data.length == 0)
                throw new NullPointerException("数据处理出错!");
            //取出长度
            // int length = bys[0] << 8 & 0xFF00 | bys[1] & 0xFF;
            OutputStream outputStream = Client_sslSocket.getOutputStream();
            outputStream.write(data);
            // 发送读取的数据到服务端
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            Log.e(this.getClass().getName(),"OutputStream获取失败!");
        }

    }
  1. 读取数据
public String read(){
        try{
            InputStream in = Client_sslSocket.getInputStream();
            byte buffer[] = new byte[1024];
            int temp = 0;
            int count = 0;
            temp = in.read(buffer);
            String str = "";
            if(temp != -1){
               //前两位表示返回数据的长度 11是拼接的固定头数据,如果没有不用减11
                int length = buffer[0] << 8 & 0xFF00 | buffer[1] & 0xFF;
                byte[] result = new byte[length - 11];
                if (length < 1022){
                    System.arraycopy(buffer,13,result,0,length - 11);
                }else {
                    System.arraycopy(buffer,13,result,0,1011);//1011 = 1024 - 11 - 2;
                    while ((temp = in.read(buffer)) != -1){
                        System.arraycopy(buffer,0,result,1011 + count * 1024,temp);
                        count++;
                    }
                }
               str = new String(result, "UTF-8");
            }
            
            in.close();
            return str;
        } catch (UnsupportedEncodingException e) {
            Log.e(this.getClass().getName(),"数据编码格式错误!");
        } catch (IOException e) {
            Log.e(this.getClass().getName(),"InputStream获取失败!");
        }
        return "";
    }

5.关闭连接

public void close(){
        try {
            Client_sslSocket.close();
        } catch (IOException e) {
            Log.e(this.getClass().getName(),"连接关闭失败" + "  :" + e.getMessage().toString());
        }
    }

你可能感兴趣的:(SSL+Socket 初步整理)