前一阵给公安局做项目,用到了公钥加密技术及对称密钥加密技术。信息通过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;
}
}
新闻热点
疑难解答