加密|解決|資料
前一陣給公安局做項目,用到了公開金鑰加密技術及對稱金鑰密碼編譯技術。資訊通過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;
}
}