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