前一陣給公安局做項目,用到了公鑰加密技術及對稱密鑰加密技術。信息通過3des進行加密,而密鑰通過rsa公鑰體系傳送。客戶端使用cpu卡ekey進行解密。但是在系統編寫過程中發現,.net中的rsa加密算法為了提高安全性,在待加密數據前要添加一些隨機數,因此,使用.net中的rsa加密算法一次最多加密117字節數據(多于117字節需要拆分成多段分別加密再連接起來),經過加密后得到一個長度為128字節的加密數據。但這對于需要進行收發雙方身份確認的公鑰體系來說會帶來不少麻煩。在我的系統中,我需要通過以下步驟實現對用戶會話密鑰的網上加密傳遞:
加密過程:
1、對會話密鑰添加隨機數,補充到128位,
2、使用ca私鑰解密,結果為128位數據,
3、對數據使用用戶公鑰加密,得到128位數據,通過網絡傳送。
解密過程:
1、使用用戶私鑰解密網上傳送的128位數據;
2、將結果使用ca公鑰加密;
3、去掉用來混淆的隨機數,提取出會話密鑰
但.net中的rsa加密最多只能對117字節數據進行操作,導致128位數據不得不分兩部分進行處理,于是加密數據不斷膨脹。為了解決這個問題,并使得rsa加密、解密過程與ekey上的過程相一致,我只好編寫自己的rsa加密算法。
經過查找了大量資料后,我決定利用現成的 biginteger 類。可以參考http://www.codeproject.com/csharp/biginteger.asp 得到更多的信息。利用 biginteger,我添加了兩個方法rsaencrypt和rsadecrypt,實現rsa加密解密。這樣就再也不用受117字節的限制了。
下面給出了兩段程序,程序一是使用.net自帶rsa加密算法實現加密解密,不過 textlength 屬性一旦超過 117,系統將無法加密; 程序二是經過改造的系統,可以對128位的數據進行加密,沒有了117的限制。程序二省略了biginteger類,需要的話可以從http://www.codeproject.com/csharp/biginteger.asp下載,不要忘了注釋其中的main方法,否則在編譯時會有一個編譯錯誤,說有兩個入口點(當然也可以在項目屬性中指定一個入口點)。
程序一:
using system;
using system.security.cryptography;
using system.text;
class oldrsa
...{
static void main()
...{
int textlength = 117;
byte[] encrypteddata;
byte[] decrypteddata;
string key1 = "<rsakeyvalue><modulus>4n6ejsx4qnfpp6h+wcpdjz8ssmmrjevjabqegsoobhknepo/v3m94nf89+zl5llh7/lurgcufnizvieth/z9+h/ydum0f3fjimn3utk1tk0ioff0cvc9lnerbeoejmkeqivujuc4c+bmqttn6urhfcy3r3zgp3feegqorljekvc=</modulus><exponent>aqab</exponent><p>7w2qsvrbn168ehc4v/fipml+7wukorrij9i8i21fs5glvyrja2czbzplkrahumloclgd/qkj0iapf17471nfkw==</p><q>8oztalinrk1vduvlhnppcnqsehbp9if5p+kwru07sfgwahnyewurg0epebvbgoe/1kzpkqb/wu8vsn4oeauohq==</q><dp>dih+5ouww5av7zlifvqdtents8b9uzbhcbvxry2vddaxbdr+swbse/gvmrg/9fmwk6zbhbopnj8tchkmqozhuq==</dp><dq>6g96q/gxeug3qk+dbp8hil9vsex5wd8ueigicv9/as/7iwqljgbama1xi8txrbo6mdbil2pgkf4uqeg5qeqzrq==</dq><inverseq>nyx28u1freiigxgx2s5+pxbb8wq0xvxne2g2mt0vq9xqdhbaxefpfznjnaga8ahvlunahqg5urgry3ogqono4g==</inverseq><d>pvkj1r1ntc3lhu+xgitvq9qe0tr9v6rcy7sfov9xbcm/ypf20q8sod3y0ad87u9ccssdwfjyagukai0wugjfgfalf8/4pfwqzrgblsn96klmklmy7c6oihlriw+myxmvaggsp3/r4se6wgk5ischjkikyv/pywoobdre6ordzie=</d></rsakeyvalue>";
try
...{
rsacryptoserviceprovider rsa = new rsacryptoserviceprovider();
rsa.fromxmlstring(key1);
byte[] datatoencrypt = generatebytes(textlength);
console.writeline("original buff: " + convert.tobase64string(datatoencrypt) + " ");
encrypteddata = rsa.encrypt(datatoencrypt, false);
console.writeline("encrypted buff: " + convert.tobase64string(encrypteddata) + " ");
decrypteddata = rsa.decrypt(encrypteddata,false);
console.writeline("decrypted buff: " + convert.tobase64string(decrypteddata) + " ");
}
catch
...{
console.writeline("encryption failed.");
}
}
//***********************************************************************
// 隨機生成一指定長度的字節數組
//***********************************************************************
public static byte[] generatebytes(int bytelength)
...{
byte[] buff = new byte[bytelength];
rngcryptoserviceprovider rng = new rngcryptoserviceprovider();
// 該數組已使用密碼增強的隨機字節進行填充
rng.getbytes(buff);
return buff;
}
}
程序二:
using system;
using system.security.cryptography;
using system.text;
class newrsa
...{
public static void main()
...{
int textlength = 128;
byte[] encrypteddata;
byte[] decrypteddata;
string key1 = "<rsakeyvalue><modulus>4n6ejsx4qnfpp6h+wcpdjz8ssmmrjevjabqegsoobhknepo/v3m94nf89+zl5llh7/lurgcufnizvieth/z9+h/ydum0f3fjimn3utk1tk0ioff0cvc9lnerbeoejmkeqivujuc4c+bmqttn6urhfcy3r3zgp3feegqorljekvc=</modulus><exponent>aqab</exponent><p>7w2qsvrbn168ehc4v/fipml+7wukorrij9i8i21fs5glvyrja2czbzplkrahumloclgd/qkj0iapf17471nfkw==</p><q>8oztalinrk1vduvlhnppcnqsehbp9if5p+kwru07sfgwahnyewurg0epebvbgoe/1kzpkqb/wu8vsn4oeauohq==</q><dp>dih+5ouww5av7zlifvqdtents8b9uzbhcbvxry2vddaxbdr+swbse/gvmrg/9fmwk6zbhbopnj8tchkmqozhuq==</dp><dq>6g96q/gxeug3qk+dbp8hil9vsex5wd8ueigicv9/as/7iwqljgbama1xi8txrbo6mdbil2pgkf4uqeg5qeqzrq==</dq><inverseq>nyx28u1freiigxgx2s5+pxbb8wq0xvxne2g2mt0vq9xqdhbaxefpfznjnaga8ahvlunahqg5urgry3ogqono4g==</inverseq><d>pvkj1r1ntc3lhu+xgitvq9qe0tr9v6rcy7sfov9xbcm/ypf20q8sod3y0ad87u9ccssdwfjyagukai0wugjfgfalf8/4pfwqzrgblsn96klmklmy7c6oihlriw+myxmvaggsp3/r4se6wgk5ischjkikyv/pywoobdre6ordzie=</d></rsakeyvalue>";
try
...{
rsacryptoserviceprovider rsa = new rsacryptoserviceprovider();
rsa.fromxmlstring(key1);
rsaparameters rsakeyinfo = rsa.exportparameters(true);
byte[] datatoencrypt = generatebytes(textlength);
console.writeline("original buff: " + convert.tobase64string(datatoencrypt) + " ");
encrypteddata = rsaencrypt(datatoencrypt, rsakeyinfo.exponent, rsakeyinfo.modulus);
console.writeline("encrypted buff: " + convert.tobase64string(encrypteddata) + " ");
decrypteddata = rsadecrypt(encrypteddata, rsakeyinfo.d, rsakeyinfo.modulus);
console.writeline("decrypted buff: " + convert.tobase64string(decrypteddata) + " ");
}
catch
...{
console.writeline("encryption failed.");
}
}
//***********************************************************************
// rsa encrypt
//***********************************************************************
static public byte[] rsaencrypt(byte[] datatoencrypt, byte[] exponent, byte[] modulus)
...{
biginteger original = new biginteger(datatoencrypt);
biginteger e = new biginteger(exponent);
biginteger n = new biginteger(modulus);
biginteger encrypted = original.modpow(e,n);
return hexstringtobyte(encrypted.tohexstring());
}
//***********************************************************************
// rsa decrypt
//***********************************************************************
static public byte[] rsadecrypt(byte[] encrypteddata, byte[] d, byte[] modulus)
...{
biginteger encrypted = new biginteger(encrypteddata);
biginteger d = new biginteger(d);
biginteger n = new biginteger(modulus);
biginteger decrypted = encrypted.modpow(d,n);
return hexstringtobyte(decrypted.tohexstring());
}
//***********************************************************************
// 將 hexstring 轉換為 byte[] 數組
//***********************************************************************
static public byte[] hexstringtobyte(string hexstring)
...{
byte[] byteresult = new byte[hexstring.length/2];
for(int i = 0; i < hexstring.length/2; i++)
byteresult[i] = convert.tobyte(hexstring.substring(i*2,2),16);
return byteresult;
}
//***********************************************************************
// 隨機生成一指定長度的字節數組
//***********************************************************************
public static byte[] generatebytes(int bytelength)
...{
byte[] buff = new byte[bytelength];
rngcryptoserviceprovider rng = new rngcryptoserviceprovider();
// 該數組已使用密碼增強的隨機字節進行填充
rng.getbytes(buff);
return buff;
}
}
新聞熱點
疑難解答