top
Loading...
Java安全通信、數字證書及應用實踐
摘要

在本文中,我用詳細的語言和大量的圖片及完整的程序源碼向你展示了在 JAVA中如何實現通過消息摘要、消息驗證碼達到安全通信、以及用Java的工具生成數字證書,和用程序給數字證書簽名、以及用簽名后的數學證書簽名applet突破applet的訪問權限的過程,給出了全部例子的詳細代碼。

通過本文中你可以學到以下知識:

程序間如何安全通信

什么是 及 如何生成消息摘要

什么是 及 如何生成消息驗證碼

如何使用 Java工具生成和維護數字證書庫

如何用程序給數字證書驗證簽名

如何利用數字證書給 applet簽名突破applet的訪問權限

關鍵字

消息摘要、消息驗證碼、指紋、加密、安全、 Java、數字簽名、applet、數字證書

一、基礎知識

計算機安全通信過程中,常使用消息摘要和消息驗證碼來保證傳輸的數據未曾被第三方修改。

消息摘要是對原始數據按照一定算法進行計算得到的結果,它主要檢測原始數據是否被修改過。消息摘要與加密不同,加密是對原始數據進行變換,可以從變換后的數據中獲得原始數據,而消息摘要是從原始數據中獲得一部分信息,它比原始數據少得多,因此消息摘要可以看作是原始數據的指紋。

例:下面一段程序計算一段字符串的消息摘要

package com.messagedigest;
import java.security.*;
public class DigestPass {
public static void main(String[] args) throws Exception{
String str="Hello,I sent to you 80 yuan.";
MessageDigest md = MessageDigest.getInstance("MD5");//常用的有MD5,SHA算法等
md.update(str.getBytes("UTF-8"));//傳入原始字串
byte[] re = md.digest();//計算消息摘要放入byte數組中
//下面把消息摘要轉換為字符串
String result = "";
for(int i=0;i<re.length;i++){
result += Integer.toHexString((0x000000ff&re[i])|0xffffff00).substring(6);
}
System.out.println(result);
}
}

當我們有時需要對一個文件加密時,以上方式不再適用。

又例:下面一段程序計算從輸入(出)流中計算消息摘要。

package com.messagedigest;
import java.io.*;
import java.security.*;
public class DigestInput {
public static void main(String[] args) throws Exception{
String fileName = "test.txt";
MessageDigest md = MessageDigest.getInstance("MD5");
FileInputStream fin = new FileInputStream(fileName);
DigestInputStream din = new DigestInputStream(fin,md);//構造輸入流
//DigestOutputStream dout = new DigestOutputStream(fout,md);
//使用輸入(出)流可以自己控制何時開始和關閉計算摘要
//也可以不控制,將全過程計算
//初始時是從開始即開始計算,如我們可以開始時關閉,然后從某一部分開始,如下:
//din.on(false);
int b;
while((b=din.read())!=-1){
//做一些對文件的處理
//if(b=='$') din.on(true); //當遇到文件中的符號$時才開始計算
}
byte[] re = md.digest();//獲得消息摘要
//下面把消息摘要轉換為字符串
String result = "";
for(int i=0;i<re.length;i++){
result += Integer.toHexString((0x000000ff&re[i])|0xffffff00).substring(6);
}
System.out.println(result);
}
}

當A和B通信時,A將數據傳給B時,同時也將數據的消息摘要傳給B,B收到后可以用該消息摘要驗證A傳的消息是否正確。這時會產生問題,即若傳遞過程中別人修改了數據時,同時也修改了消息摘要。B就無法確認數據是否正確。消息驗證碼可以解決這一問題。

使用消息驗證碼的前提是 A和B雙方有一個共同的密鑰,這樣A可以將數據計算出來的消息摘要加密后發給B,以防止消息摘要被改。由于使用了共同的密鑰,所以稱為“驗證碼”。

例、下面的程序即可利用共同的密鑰來計算消息摘要的驗證碼

package com.mac;
import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class MyMac {
public static void main(String[] args) throws Exception{
//這是一個消息摘要串
String str="TestString";
//共同的密鑰編碼,這個可以通過其它算法計算出來
byte[] kb={11,105,-119,50,4,-105,16,38,-14,-111,21,-95,70,-15,76,-74,
67,-88,59,-71,55,-125,104,42};
//獲取共同的密鑰
SecretKeySpec k = new SecretKeySpec(kb,"HMACSHA1");
//獲取Mac對象
Mac m = Mac.getInstance("HmacMD5");
m.init(k);
m.update(str.getBytes("UTF-8"));
byte[] re = m.doFinal();//生成消息碼
//下面把消息碼轉換為字符串
String result = "";
for(int i=0;i<re.length;i++){
result += Integer.toHexString((0x000000ff&re[i])|0xffffff00).substring(6);
}
System.out.println(result);
}
}

使用以上兩種技術可以保證數據沒有經過改變,但接收者還無法確定數據是否確實是某個人發來的。盡管消息碼可以確定數據是某個有同樣密鑰的人發來的,但這要求雙方具有共享的密鑰,若有一組用戶共享,我們就無法確定數據的來源了。

數字簽名可以解決這一問題。數字簽名利用非對稱加密技術,發送者使用私鑰加密數據產生的消息摘要(簽名),接收者使用發送者的公鑰解密消息摘要以驗證簽名是否是某個人的。由于私鑰只有加密者才有,因此如果接收者用某個公鑰解密了某個消息摘要,就可以確定這段消息摘要必然是對應的私鑰持有者發來的。

使用數字簽名的前提是接收數據者能夠確信驗證簽名時(用發送者的私鑰加密消息摘要)所用的公鑰確實是某個人的 (因為有可能有人假告公鑰)。數字證書可以解決這個問題。

數字證書含有兩部分數據:一部分是對應主體(單位或個人)的信息,另一部分是這個主體所對應的公鑰。即數字證書保存了主體和它的公鑰的一一對應關系。同樣,數字證書也有可能被假造,如何判定數字證書的內容的真實性呢?所以,有效的數字證書必須經過權威 CA的簽名,即權威CA驗證數字證書的內容的真實性,然后再在數字證書上使用自己的私鑰簽名(相當于在證書加章確認)。

這樣,當用戶收到這樣的數字證書后,會用相應的權威 CA的公鑰驗證該證書的簽名(因為權威的CA的公鑰在操作系統中己經安裝)。根據非對稱加密的原理,如果該證書不是權威CA簽名的,將不能通過驗證,即該證書是不可靠的。

若通過驗證,即可證明此證書含的信息(發信人的公鑰和信息)是無誤的。于是可以信任該證書,便可以通過該證書內含的公鑰來確認數據確實是發送者發來的。

于是,雙方通信時, A把數據的消息摘要用自己的私鑰加密(即簽名),然后把自己的數字證書和數據及簽名后的消息摘要一起發送給B,B處查看A的數字證書,如果A的數字證書是經過權威CA驗證可靠的,便信任A,便可使用A的數字證書中附帶的A的公鑰解密消息摘要(這一過程同時確認了發送數據的人又可以解密消息摘要),然后通過解密后的消息摘要驗證數據是否正確無誤沒被修改。

利用這一原理,我們可以突破 java的applet小程序在瀏覽器中的權限,由于默認的applet權限控制不允許它訪問操作系統級的一切。于是我們可以用我們數字證書來給applet簽名,然后客戶端收到該applet時,系統會自動查看給該applet簽名的數字證書并提供給終端用戶判定是否信認該數字證書,如果用戶信認,則該applet便有了訪問系統的權限。

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗