隨著計算機網絡技術和軟件技術的蓬勃發展,以及internet的廣泛應用對傳統的工作方式產生的巨大沖擊,電子政務(E-government)系統就在這樣的環境下應運而生了。電子政務的所有活動都是政府行為,要求具有高度的可靠性和安全性。數字簽名技術這種能保證數據的完整性、機密性、抗否定性的信息安全技術毫無疑問將會在電子政務系統中得到廣泛的應用。由于java在網絡編程中的適用性,以及java的安全系統結構的日益完善和目前java開發網絡安全軟件的便利性,因此在電子政務系統中用java來實現數字簽名會具有更好的現實意義。
數字簽名的流程
數字簽名是相對于手書簽名而言的,是指采用一定的數據交換協議,使用密碼算法對待發的數據(如文件、合同、通知等)進行加密處理后,生成一段信息,附著在原文上一起發送,這段信息類似現實中的簽名或印章,接收方對其進行驗證,判斷發送者的身份和原文真偽。
數字簽名主要是采用非對稱加密算法,先采用單向Hash函數,將待發送的數據生成消息摘要MD_1,發送方使用自己的私鑰對消息摘要加密生成數字簽名,將數字簽名附著在原文上一起發送。接收方收到消息以后,先用發送方的公鑰將簽名解密,得到消息摘要。然后利用接收的原數據進行單向Hash函數的計算,得到消息摘要MD_2進行驗證,如果MD_1=MD_2,說明簽名成功。
數字簽名的流程如圖(一)所示:

從流程圖可以看出,數字簽名包括簽名算法和驗證算法,目前主要使用的簽名算法有RSA和DSA。
從數字簽名的原理和流程圖我們可以看出,數字簽名主要有以下幾方面的功能:
(1)保證了信息的完整性。根據Hash函數的性質,一旦原始信息被改動,所生成的數字摘要就會發生很大的變化。因此,通過這種方式,能防止原始信息被篡改。
(2)抗否認性。使用公開密鑰的加密算法,由于只有發送方一人擁有私鑰,因此,發送方不能否認發送過信息。
(3)防止接收方偽造一份報文,聲稱來自于發送方。
java在實現數字簽名方面的優勢
java在實現數字簽名方面有很大的優勢,主要表現在以下幾個方面:
1、Java平臺為安全和加密服務提供了兩組API:JCA和JCE;
2、JCA (Java Cryptography Architecture)提供基本的加密框架,如證書、數字簽名、消息摘要和密鑰對產生器;
3、JCE在JCA的基礎上作了擴展,包括加密算法、密鑰交換、密鑰產生和消息鑒別服務等接口。
在電子政務系統中使用混合密碼體制來實現數字簽名技術
在電子政務系統中如果在數字簽名時原文在網絡上以明文傳輸,就不能保證原始信息的機密性,而要保證原始信息的機密性,就需要對待發送的原始信息實行加密運算,若對原文使用非對稱密碼算法,由于使用非對稱密碼算法在解密時運算量很大,將會影響運算速度。所以,選擇使用對稱密碼算法對原文進行加密,而用非對稱的密碼算法來實現數字簽名技術,使用這種混合密碼體制,既能實現數字簽名,保證了在傳輸過程中原文機密性,又能提高運算效率。
使用混合密鑰的數字簽名流程如圖(二)所示:

用java語言來實現混合密鑰的數字簽名
前面已經提到了java2為實施安全策略提供了很多機制,因此在電子政務中要實現數字簽名選用java作為軟件的開發平臺是一個可行的方案,下面就給出一個實例的主要算法說明用java2是怎樣實現數字簽名的。因為是用在電子政務系統中,接收和發送文件的雙方通常都比較固定,這里就不考慮公鑰傳送的安全問題,先假定接收方使用的公鑰即為發送方使用的私鑰所對應的公鑰,算法中生成消息摘要的算法為MD5,簽名算法使用RSA,對原文進行對稱加密算法使用DES:
Java2中需要用到的主要的類基本上都封裝在java.security.*和javax.crypto.*兩個包中。
(1)引入需要用的java包
/*包含輸入輸出的類*/
Import java.io.*;
/*包含密鑰對生成器類、密鑰管理類、簽名類*/
Import java.security.*;
/*包含各種密碼算法類如:DES和RSA等*/
Import javax.crypto.*;
(2)發送方的代碼( 假設要傳送的數據是保存在文件info.dat中的):
/*生成RSA算法的公鑰pubKey和私鑰priKey,這里假定公鑰生成以后是通過第三方安全的發送給接收方的*/
KeyPairGenerator DoublekeyGen = KeyPairGenerator.getInstance(“RSA”);
DoublekeyGen.init(1024);
KeyPair DoubleKey = DoublekeyGen.generateKeyPair();
PrivateKey priKey = DoubleKey.getPrivate();
PublicKeypubKey = DoubleKey.getpublic();
/* 將公鑰pubKey保存在文件pubKey.dat文件中,供接收方使用*/ ObjectOutputStream out = new.ObjectOutputStream(newFileOutputStream(“pubKey.dat”);
out.writeObject(pubKey);
out.close();
/*生成DES算法的密鑰Key*/
KeyPairGenerator SinglekeyGen = KeyGenerator.getInstance(“DES”);
SinglekeyGen.init(64);
Key SingleKey = SinglekeyGen.generateKey();
/*從文件info.dat讀出需要傳輸的原始數據并保存在數組info_Plain[ ]中*/
ObjectInputStream in=new ObjectInputStream(new FileInputStream(“info.dat”));
byte[ info_Plain=(byte[ ])in.readObject();
in.close();
/*將待傳輸的原始信息生成消息摘要MD_1*/
MessageDigest messageDigest = MessageDigest.getInstance(“MD5”);
messageDigest.update(info_Plain);
byte[ ] MD_1 = messageDigest.digest();
/* 將待傳輸的信息用DES加密,并將加密后的數據保存在數組Des_info[ ]中*/
Ciphercipher = cipher.getInstance(“DES”);cipher.init(Cipher.ENCRYPT_MODE,SingleKey);
byte[ ] Des_info[ ] = cipher.doFinal(info_plain);
/* 將消息摘要MD_1[ ]和對稱密鑰SingleKey合并到字節數組MD_Key[ ]中,并用RSA算法中的私鑰對該數組加密并保存在數組Rsa_sign[ ]中形成了數字簽名*/
合并數組的算法略(主要就是通過循環將對稱密鑰添加到消息摘要數組的后面,形成一個新的數組MD_Key[ ],對稱密鑰要通過強制類型轉化為byte類型)
Cipher cipher = cipher.getInstance(“RSA”);
cipher.init(Cipher.ENCRYPT_MODE, priKey);
byte[ ]Rsa_sign[ ] = cipher.doFinal(MD_Key);
/*將需要傳輸的原文的密文和數字簽名寫到文件En_info.dat中,En_info.dat即為在網上傳輸的信息*/
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“En_info.dat));
Out.writeobject(Des_info);
Out.writeobject(Rsa_sign);。
Out.close();
(3)接收方的代碼
接受方收到文件En_info.dat,該文件信息由兩部分組成○1原文的密文:保存數組Des_info[ ];○2發送方的數字簽名:保存在Rsa_sign[ ]數組中;并從pubKey.dat文件中將公鑰讀出且保存在變量PubKey中。
/*從文件En_info.dat中讀出原文的密文和數
字簽名兩個數組*/
此部分算法略
/*將數字簽名保存在Rsa_sign[ ]數組中用發送方的公鑰解密得到消息摘要和對稱密鑰組成的數組MD_Key[ ]*/
公鑰解密的算法略(解密和加密算法基本相同)
Int len = MD_Key.length();
Byte[ ]MD_1 = new Byte[ ];
Byte[ ]Key =new Byte[ ]
For (int i=0; i<128;i++)/*因為用MD5產生的數字摘要為128位*/
MD_1[i]=Md_Key[i];/*將摘要部分提取出來賦給數組MD_1*/
/*數組中的128位以后的元素即為對稱密鑰*/
While(i {Key[i]=Md_Key[i];}/*將對稱密鑰提取出來賦給數組Key[ ]*/ Key SingleKey = (PrivateKey)key; /*將對稱密鑰強制類型轉換為key型*/ /*得到對稱密鑰后,通過DES的解密算法將密文變成明文,再將明文用MD5算法生成消息摘要并保存在數組MD_2[ ]中*/ 解密和生成消息摘要的算法略 /*將MD_1[ ] 和MD_2[ ]做比較,若相等,則簽名正確*/ For(int i=0;i<128;i++) { if MD_1[i] != MD_2[i] { System.out.println(“Signature error!”); System.exit.( ); } } System.out.println(“Signature success!”); 由于只是給出了主要的算法,沒有考慮在程序的執行過程中可能出現的異常情況以及一些基本的輸入輸出語句。