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)
- 準(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";//
- 生成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();
}
}
- 發(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獲取失??!");
}
}
- 讀取數(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());
}
}