SSL+Socket 初步整理

SSL概念

SSL(Secure Sockets Layer,安全套接層),安全套接層是Netscape公司率先采用的網(wǎng)絡(luò)安全協(xié)議。它是在傳輸通信協(xié)議(TCP/IP)上實(shí)現(xiàn)的一種安全協(xié)議,采用公開密鑰技術(shù)。SSL廣泛支持各種類型的網(wǎng)絡(luò),同時提供三種基本的安全服務(wù),它們都使用公開密鑰技術(shù)。

其繼任者傳輸層安全(Transport Layer Security,TLS)是為網(wǎng)絡(luò)通信提供安全及數(shù)據(jù)完整性的一種安全協(xié)議。TLS與SSL在傳輸層對網(wǎng)絡(luò)連接進(jìn)行加密。

Socket概念

網(wǎng)絡(luò)上的兩個程序通過一個雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個連接的一端稱為一個socket。

建立網(wǎng)絡(luò)通信連接至少要一對端口號(socket)。socket本質(zhì)是編程接口(API),對TCP/IP的封裝,TCP/IP也要提供可供程序員做網(wǎng)絡(luò)開發(fā)所用的接口,這就是Socket編程接口;HTTP是轎車,提供了封裝或者顯示數(shù)據(jù)的具體形式;Socket是發(fā)動機(jī),提供了網(wǎng)絡(luò)通信的能力。

Socket的英文原義是“孔”或“插座”。作為BSD UNIX的進(jìn)程通信機(jī)制,取后一種意思。通常也稱作"套接字",用于描述IP地址和端口,是一個通信鏈的句柄,可以用來實(shí)現(xiàn)不同虛擬機(jī)或不同計算機(jī)之間的通信。在Internet上的主機(jī)一般運(yùn)行了多個服務(wù)軟件,同時提供幾種服務(wù)。每種服務(wù)都打開一個Socket,并綁定到一個端口上,不同的端口對應(yīng)于不同的服務(wù)。Socket正如其英文原義那樣,像一個多孔插座。一臺主機(jī)猶如布滿各種插座的房間,每個插座有一個編號,有的插座提供220伏交流電, 有的提供110伏交流電,有的則提供有線電視節(jié)目。 客戶軟件將插頭插到不同編號的插座,就可以得到不同的服務(wù)。

客戶端證書生成

服務(wù)端給我們一個服務(wù)端的.pem格式的證書,通過Java指令將服務(wù)端證書添加到我們的密鑰庫中,生成我們的證書
keytool -import -alias 別名 -file 服務(wù)端證書路徑 -storetype 密鑰庫(如 :JKS、BKS) -storepass 密碼 -keystore (路徑非必需)+ 文件名 -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-1.46.jar(換成自己的jar)

這里的storetype如果是Java服務(wù)用JKS,Android用BKS
后邊的provider如果不用的話可能會在加載密鑰庫的時候出錯,并且后邊用的jar包如果1.46不可以的話可以換換版本試試,比如1.45。

代碼實(shí)現(xiàn)

  1. 準(zhǔn)備好必要的參數(shù)
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";//使用協(xié)議
private static final String CLIENT_KEY_MANAGER = "X509";//密鑰管理器(如果是Java服務(wù)此處為SunX509)
private static final String CLIENT_TRUST_MANAGER = "X509";//
private static final String CLIENT_KEY_KEYSTORE = "BKS";//密庫,這里用的是BouncyCastle密庫(Java服務(wù)為JKS)
private static final String CLIENT_TRUST_KEYSTORE = "BKS";//    
  1. 生成SSLSocket對象
public void init(Context context) {
    try {
        //取得KeyManagerFactory和TrustManagerFactory的X509密鑰管理器實(shí)例
        KeyManagerFactory keyManager = KeyManagerFactory.getInstance(CLIENT_KEY_MANAGER);
        TrustManagerFactory trustManager = TrustManagerFactory.getInstance(CLIENT_TRUST_MANAGER);
        //取得BKS密庫實(shí)例
        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實(shí)例
        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. 發(fā)送數(shù)據(jù)
public void write(String body){
        try {
            byte data[] = dataProcessing(body);
            if (data == null || data.length == 0)
                throw new NullPointerException("數(shù)據(jù)處理出錯!");
            //取出長度
            // int length = bys[0] << 8 & 0xFF00 | bys[1] & 0xFF;
            OutputStream outputStream = Client_sslSocket.getOutputStream();
            outputStream.write(data);
            // 發(fā)送讀取的數(shù)據(jù)到服務(wù)端
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            Log.e(this.getClass().getName(),"OutputStream獲取失??!");
        }

    }
  1. 讀取數(shù)據(jù)
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){
               //前兩位表示返回數(shù)據(jù)的長度 11是拼接的固定頭數(shù)據(jù),如果沒有不用減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(),"數(shù)據(jù)編碼格式錯誤!");
        } catch (IOException e) {
            Log.e(this.getClass().getName(),"InputStream獲取失?。?);
        }
        return "";
    }

5.關(guān)閉連接

public void close(){
        try {
            Client_sslSocket.close();
        } catch (IOException e) {
            Log.e(this.getClass().getName(),"連接關(guān)閉失敗" + "  :" + e.getMessage().toString());
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容