JAVA安全體系結(jié)構(gòu)分析
?
下圖顯示了
JAVA
安全體系結(jié)構(gòu)的標(biāo)準(zhǔn)組件。在圖的下半部分,是
JAVA2
安全體系結(jié)構(gòu)的核心和
JAVA
加密體系結(jié)構(gòu)(
JCA
,
Java Cryptography Architecture
),兩者構(gòu)成
JAVA2
平臺(tái)所帶的
JAVA2
安全平臺(tái)。在圖的上半部分,是獨(dú)立于
JAVA2
平臺(tái)而又與
JAVA2
平臺(tái)的不同方面相關(guān)的
JAVA
安全擴(kuò)展。
JCA與JCE?
??
?
??? JCA/JCE并不執(zhí)行各種算法,它們只是連接應(yīng)用和實(shí)際算法實(shí)現(xiàn)程序的一組接口。軟件開發(fā)商根據(jù)JCE接口,將各種算法實(shí)現(xiàn)后,打包成一個(gè)Provider,可以動(dòng)態(tài)地加到Java運(yùn)行環(huán)境中。由于美國(guó)出口控制規(guī)定,JCA?是可出口的(JCA和一個(gè)Sun的默認(rèn)實(shí)現(xiàn)包括在Java2中),但是JCE對(duì)部分國(guó)家是限制出口的。因此,要實(shí)現(xiàn)一個(gè)完整的安全結(jié)構(gòu),就需要一個(gè)或多個(gè)第三方廠商提供的JCE產(chǎn)品,稱為安全供應(yīng)者。
BouncyCastle JCE
就是其中的一個(gè)
安全供應(yīng)者。
???? 安全供應(yīng)者是承擔(dān)特定安全機(jī)制的實(shí)現(xiàn)的第三方。有些供應(yīng)者是完全免費(fèi)的,而另一些供應(yīng)者則需要付費(fèi)。提供安全供應(yīng)者的公司有IBM,Bouncy Castle等,Sun提供了如何實(shí)現(xiàn)開發(fā)人員自己供應(yīng)者的細(xì)節(jié)。Bouncy Castle提供了可以在J2ME/J2EE/J2SE平臺(tái)得到支持的API,而且他的API是免費(fèi)的。詳情參見:http://www.bouncycastle.org/。
安裝BouncyCastleJCE
安裝
BouncyCastle
JCE應(yīng)該按照如下步驟:
1)
下載提供者
如上,
BouncyCastle
可以從
www.bouncycastle.org
下載,下載后請(qǐng)將它解
壓縮。
2)
將
JAR
文件拷貝到適當(dāng)位置
如果想讓
JCE
類可以被所有的
JAVA
應(yīng)用程序使用,我們需要把
JAR
文件安裝為一個(gè)擴(kuò)展。
BouncyCastle
提供者沒有用于安裝為擴(kuò)展的
JAR
文件,但它容易構(gòu)建。首先將下載的文件展開到
JDK
的
classes
目錄下,然后運(yùn)行下面的命令將這些文件打包:
c:\> jar cvf bouncycastle.jar javax org
在
Windows
中,
Java
通常安裝在兩個(gè)目錄下。一個(gè)目錄用于開發(fā),包括所有的
JDK
工具,另一個(gè)僅僅是運(yùn)行環(huán)境。
JDK
本身通常位于
c:\jdk1.3
這樣的目
錄下,而JDK運(yùn)行環(huán)境通常位于c:\Program files\JavaSoft\JRE1.3這樣的目錄下,它們都有庫(kù)的擴(kuò)展目錄。分別是:c:\jdk1.3.1\lib\ext和c:\Program files\JavaSoft\JRE\1.3\lib\ext,把所要的JAR文件放于對(duì)應(yīng)的目錄下。
3)
配置安全屬性文件
安全屬性文件java.security位于和\lib\ext平行的另一個(gè)目錄\lib\security下,它定義了當(dāng)前可以使用的加密提供者。如您看到下面的語句:
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.rsajca.Provider
它表明本虛擬機(jī)有兩個(gè)加密提供者以及他們的優(yōu)先級(jí)和訪問時(shí)使用的名稱。當(dāng)需要用到一個(gè)加密算法時(shí),虛擬機(jī)會(huì)依次訪問這里列出的提供者,尋找想要的算法,并按這里的優(yōu)先級(jí)順序使用第一個(gè)找到的算法。
我們應(yīng)該在文件中插入如下行,把新的提供者加入進(jìn)去:
security.provider.3=org.bouncycastle.jce.provider.BouncyCastleProvider
當(dāng)然了,你也可以將前面的加密提供者配置刪除,這樣就不能使用jdk默認(rèn)的加密提供者了。
4)測(cè)試安裝好的程序
我們可以自己寫一個(gè)測(cè)試程序(用JCE包的API),來判斷我們的安裝是否成功。
安裝成功了,讓我們進(jìn)入用
BouncyCastle JCE
實(shí)現(xiàn)安全功能的有趣天地吧
!
??? 對(duì)稱加密采用了對(duì)稱密碼編碼技術(shù),它的特點(diǎn)是文件加密和解密使用相同的密鑰,即加密密鑰也可以用作解密密鑰。這種方法在密碼學(xué)中叫做對(duì)稱加密算法,對(duì)稱加密算法使用起來簡(jiǎn)單快捷,密鑰較短,且破譯困難,除了數(shù)據(jù)加密標(biāo)準(zhǔn)(DES),另一個(gè)對(duì)稱密鑰加密系統(tǒng)系統(tǒng)是國(guó)際數(shù)據(jù)加密算法(IDEA),它比DES的加密性好,而且對(duì)計(jì)算機(jī)功能要求也沒有那么高。IDEA加密標(biāo)準(zhǔn)由PGP(Pretty Good Privacy)系統(tǒng)使用。
對(duì)稱加密的實(shí)現(xiàn)
*?鏈接加密:在網(wǎng)絡(luò)節(jié)點(diǎn)間加密,在節(jié)點(diǎn)間傳輸加密,傳送到節(jié)點(diǎn)后解密,不同節(jié)點(diǎn)對(duì)間用不同密碼.?
*?節(jié)點(diǎn)加密:與鏈接加密類似,不同的只是當(dāng)數(shù)據(jù)在節(jié)點(diǎn)間傳送時(shí),不用明碼格式傳送,而是用特殊??的加密硬件進(jìn)行解密和重加密,這種專用硬件通常旋轉(zhuǎn)在安全保險(xiǎn)箱中.?
*?首尾加密:對(duì)進(jìn)入網(wǎng)絡(luò)的數(shù)據(jù)加密,然后待數(shù)據(jù)從網(wǎng)絡(luò)傳送出后再進(jìn)行解密.網(wǎng)絡(luò)本身并不會(huì)知?道正在傳送的數(shù)據(jù)是加密數(shù)據(jù).這一方法的優(yōu)點(diǎn)是,網(wǎng)絡(luò)上的每個(gè)用戶(通常是每個(gè)機(jī)器的一個(gè)??用戶)可有不同的加密關(guān)鍵詞,并且網(wǎng)絡(luò)本身不需增添任何專門的加密設(shè)備.缺點(diǎn)是每個(gè)系統(tǒng)必?須有一個(gè)加密設(shè)備和相應(yīng)的軟件(管理加密關(guān)鍵詞)或者每個(gè)系統(tǒng)必須自己完成加密工作(當(dāng)數(shù)?據(jù)傳輸率是按兆位/秒的單位計(jì)算時(shí),加密任務(wù)的計(jì)算量是很大的)
對(duì)稱解密的實(shí)現(xiàn)
對(duì)稱加密/解密算法在電子商務(wù)交易過程中存在幾個(gè)問題:
(1)?????? 要求提供一條安全的渠道使通訊雙方在首次通訊時(shí)協(xié)商一個(gè)共同的密鑰。直接的面對(duì)面協(xié)商可能是不現(xiàn)實(shí)而且難于實(shí)施的,所以雙方可能需要借助于郵件和電話等其它相對(duì)不夠安全的手段來進(jìn)行協(xié)商;
(2)?????? 密鑰的數(shù)目難于管理。因?yàn)閷?duì)于每一個(gè)合作者都需要使用不同的密鑰,很難適應(yīng)開放社會(huì)中大量的信息交流;
(3)?????? 對(duì)稱加密算法一般不能提供信息完整性的鑒別。它無法驗(yàn)證發(fā)送者和接受者的身份;
對(duì)稱密鑰的管理和分發(fā)工作是一件具有潛在危險(xiǎn)的和煩瑣的過程。對(duì)稱加密是基于共同保守秘密來實(shí)現(xiàn)的,采用對(duì)稱加密技術(shù)的貿(mào)易雙方必須保證采用的是相同的密鑰,保證彼此密鑰的交換是安全可靠的,同時(shí)還要設(shè)定防止密鑰泄密和更改密鑰的程序。
對(duì)稱解密的代碼實(shí)現(xiàn)如下:
//從密鑰文件中讀密鑰
?? SecretKey key=null;
?? try
?? {ObjectInputStream keyFile=new ObjectInputStream(
???? new FileInputStream("c:\\安全文件\\"+misClass.username+"\\對(duì)稱\\對(duì)稱密鑰\\yhb.des"));
??? key=(SecretKey)keyFile.readObject();
??? keyFile.close();
??? }
??? catch(FileNotFoundException ey1)
??? {
??? System.out.println("Error when read keyFile");
??? System.exit(0);
??? }
??? catch(Exception ey2)
??? {
??? System.out.println("error when read the keyFile");
??? System.exit(0);
??? }
?? //用key產(chǎn)生Cipher
??? Cipher cipher=null;
??? try
{
//設(shè)置算法,應(yīng)該與加密時(shí)的設(shè)置一樣
cipher=Cipher.getInstance("DES");
//設(shè)置解密模式
???? cipher.init(Cipher.DECRYPT_MODE,key);
???? }catch(Exception ey3)
???? {
???? System.out.println("Error when create the cipher");
???? System.exit(0);
???? }
???? //從對(duì)話框中取得要解密的文件并解密
???? File file=new File(dirstring,string1);
???? String filename=file.getName();
??? try
{
//輸出流,請(qǐng)注意文件名稱的獲取
BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(
????????? "c:\\安全文件\\文件\\"+filename.substring(0,filename.length()-4)));
???? //輸入流
????? CipherInputStream in=new CipherInputStream(new BufferedInputStream(
??????????? new FileInputStream(file)),cipher);
??? int thebyte=0;
??? while((thebyte=in.read())!=-1)
??? {
??? out.write(thebyte);
??? }
????? in.close();
????? out.close();
????? }
????? catch(Exception ey5)
????? {
????? System.out.println("Error when encrypt the file");
????? System.exit(0);
????? }
簽名的實(shí)現(xiàn)過程
1)讀取自己的私鑰
??? 對(duì)于自己的私鑰文件,要用File類來聲明。讀取時(shí),將用FileInputStream格式來作為輸入流。而讀出的密鑰是字節(jié)數(shù)組,所以應(yīng)該將讀出的密鑰用ByteArrayOutStream來保存,再用toByteArray格式來將它轉(zhuǎn)化為字節(jié)數(shù)組。
生成簽名要使用自己的私鑰,而私鑰使用PKCS8#編碼。所以我們還要將字節(jié)數(shù)組轉(zhuǎn)化為PKCS8#編碼形式。實(shí)現(xiàn)方法如下:
PKCS8EncodedKeySpec keyspec=new PKCS8EncodedKeySpec(keybytes);
KeyFactory keyfactory=KeyFactory.getInstance("RSA");
syprivatekey=keyfactory.generatePrivate(keyspec);
其中keybytes是從原文中讀出的字節(jié)數(shù)組形式的密鑰。用KeyFactory對(duì)象的實(shí)例化方法來指定算法,并用generatePrivate方法產(chǎn)生PKCS8#編碼的私鑰。
2)從對(duì)話框中取得要簽名的文件
該步驟的實(shí)現(xiàn)比較簡(jiǎn)單,不做過多說明。
3)將文件內(nèi)容讀取為字節(jié)數(shù)組格式
因?yàn)楹灻麜r(shí)Signature類的Update()方法的參數(shù)是字節(jié)數(shù)組形式,所以要求
先將原文讀為字節(jié)數(shù)組。并且,在此處可以獲得原文的內(nèi)容長(zhǎng)度。
4)生成簽名
按照前面的描述,先用Signature類的getInstance()方法指定MD5WithRSA
算法,然后用前面得到的私鑰作為參數(shù)調(diào)用initSign()方法來初始化,最后用原文作為參數(shù)調(diào)用update()方法來傳送數(shù)據(jù),用字節(jié)數(shù)組形式的私鑰作為參數(shù)調(diào)用Sign()方法來產(chǎn)生簽名。
將生成的簽名按照前面設(shè)計(jì)的文件格式寫入文件流中,就完成了簽名的全部工作。簽名的實(shí)現(xiàn)過程可用下面的圖來表示:
?????圖 數(shù)字簽名過程
代碼實(shí)現(xiàn)如下:
//讀取私鑰
???? PrivateKey syprivatekey=null;
????? File syfile=new File("c:\\安全文件\\"+misClass.username+"\\非對(duì)稱\\本人公私鑰\\yhb.private");
????? try
???? {
???? FileInputStream fis=new FileInputStream(syfile);
???? ByteArrayOutputStream baos=new ByteArrayOutputStream();
?
???? int thebyte=0;
????? while((thebyte=fis.read())!=-1)
????? {baos.write(thebyte);
????? }
????? fis.close();
????? byte[] keybytes=baos.toByteArray();
????? baos.close();
?
????? PKCS8EncodedKeySpec keyspec=new PKCS8EncodedKeySpec(keybytes);
????? KeyFactory keyfactory=KeyFactory.getInstance("RSA");
????? syprivatekey=keyfactory.generatePrivate(keyspec);
??? }
??? catch(Exception e9)
???? {
???? System.out.print("error when read the rsa private key");
???? System.exit(0);
???? }
???? //從對(duì)話框中取得要簽名的文件
???? File file=new File(dirstring1,string1);
???? String filename=file.getName();
???? //首先將文件讀為byte[]對(duì)象
??? int len=(int)file.length();
??? if(len>100000000)
??? {System.out.println("the file length is too long!");
??? System.exit(0);
??? }
??? byte[] inbuf=new byte[len];
??? try{
??? FileInputStream instream=new FileInputStream(file);
??? int inbytes=instream.available();
??? //inbuf[]=new byte[inbytes];
??? int bytesread=instream.read(inbuf,0,inbytes);
??? instream.close();
??? //System.out.println(inbuf);
??? }
??? catch(Exception eq2)
??? {
??? System.out.println("error when change the file to byte[]");
??? System.exit(0);
??? }
??? //簽名的具體過程
??? try{
??? //byte[] signaturebytes=new byte[150];
??? Signature sig=Signature.getInstance("MD5WithRSA");
??? sig.initSign(syprivatekey);
??? sig.update(inbuf);
??? byte[] signaturebytes=sig.sign();
?????????? //寫入對(duì)象流中
?? DataOutputStream outfile=new DataOutputStream(new FileOutputStream(
????????????????? "c:\\安全文件\\文件\\"+filename+".yhb3"));
??? outfile.writeInt(signaturebytes.length);
??? outfile.write(signaturebytes);
??? outfile.writeInt(len);
??? outfile.write(inbuf);
??? outfile.close();
??? }
??? catch(Exception eh3)
??? {
??? System.out.println("error when generate the outfile");
??? System.exit(0);
??? }
?
?