Symmetric Encrypt and Decrypt text with .NET 對稱加密和解密
There are many symmetric algorithm provided by .NET which not only can encrypt text. But I use DES with text data as an example.
You can find those symmetric algorithm under System.Security.Cryptography. RijndaelManaged, DESCryptoServiceProvider, RC2CryptoServiceProvider and RtipleDESCryptoServiceProvider are all implementation of SymmetricAlgorithm class.
.NET提供很多對稱加密法的演算法, 它們不止能對文字加密. 但我這裡以DES對文字加密作為例子. 你可以在System.Security.Cryptography找到其他對稱演算法的實作. RijndaelManaged, DESCryptoServiceProvider, RC2CryptoServiceProvider and RtipleDESCryptoServiceProvider都是SymmetricAlgorithm類別的實作.
There is two ideas we should know. We need two elements to do the encryption and decryption. An initial vector and the secret key of course. So what it the initial vector you may ask. If we encrypt the data with only using the secret key. The cypher will be in chunks all with same length. This will make it easier to break the cypher by finding pattern of a chunk. So, we use a recurrsive like mechanism to encrypt our data. Use three input to generate the output encrypted chunk. The last encrypted chunk, the current not yet encrypted chunk and the secret key. Here is where the initial vector comes in, we don’t have the ‘last encrypted chunk’ when we are at the very begining of the encryption.
有兩個概念我們要知道. 我們需要兩個元素去實行加密和解密. 一個初始向量和金鑰. 你有可能會問初始向量有甚麼用途. 如果我們用一個金鑰去做加密. 密件將會是多個同一長度的片段所組成. 這樣可以對密件的每個片段對照找出模式,比較容易破解. 所以我們用一種類似遞回的方法對我們的資料加密. 由三個輸入去產生一個加密過的片段. 分別是對上一個已加密片段, 現時還沒加密的資料片段和金鑰. 因為我們在演算法開始時並沒有’上一個加密過的片段’, 這就是要用到初始向量的時候了.
Another idea is, different symmetric algorithm have different valid key length, that is a key length range. We will see how to due with this later.
Encryption as follow :
另一個概念是, 不同的對稱加密法有不同的合法金鑰長度, 就是有一個合法的金鑰長度範圍. 我們稍後再處理這個問題.
加密如下 :
public static string EncryptToString(string PlainText, string key, string initialVector)
{
// Create a memory stream.
MemoryStream ms = new MemoryStream();
// Create the algorithm provider
DESCryptoServiceProvider l_CryptoProvider = new DESCryptoServiceProvider();
byte[] l_key = GetValidKeyFromString(key, l_CryptoProvider);
byte[] l_initialVector = System.Text.Encoding.Unicode.GetBytes(initialVector);
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, l_CryptoProvider.CreateEncryptor(l_key, l_initialVector), CryptoStreamMode.Write);
// Create a StreamWriter to write a string
// to the stream.
StreamWriter sw = new StreamWriter(encStream);
// Write the plaintext to the stream.
sw.WriteLine(PlainText);
// Close the StreamWriter and CryptoStream.
sw.Flush();
sw.Close();
encStream.Close();
// Get an array of bytes that represents
// the memory stream.
byte[] buffer = ms.ToArray();
// Close the memory stream.
ms.Close();
// Return the encrypted byte array.
// Convert to Base64 so that we can write it into text file
return Convert.ToBase64String(buffer);
}
Decryption as follow :
解密如下 :
public static string DecryptFromString(string CypherText, string key, string initialVector)
{
string val = string.Empty;
if (!string.IsNullOrEmpty(CypherText))
{
// Create a memory stream to the passed buffer.
// Convert from base64 back to binary first
byte[] l_CypherByte = Convert.FromBase64String(CypherText);
MemoryStream ms = new MemoryStream(l_CypherByte);
DESCryptoServiceProvider l_CryptoProvider = new DESCryptoServiceProvider();
byte[] l_key = GetValidKeyFromString(key, l_CryptoProvider);
byte[] l_initialVector = System.Text.Encoding.Unicode.GetBytes(initialVector);
// Create a CryptoStream using the memory stream and the
// CSP DES key.
CryptoStream encStream = new CryptoStream(ms, l_CryptoProvider.CreateDecryptor(l_key, l_initialVector), CryptoStreamMode.Read);
// Create a StreamReader for reading the stream.
StreamReader sr = new StreamReader(encStream);
// Read the stream as a string.
val = sr.ReadLine();
// Close the streams.
sr.Close();
encStream.Close();
ms.Close();
}
return val;
}
The process is not complicated, you can understand it by reading comments. Create a stream, wrap it as a crypto service provider, write/read data through the provider.
There is only one thing to talk about, the static method GetValidKeyFromString(key, l_CryptoProvider). Code as follow :
過程並不複雜, 看註解應該就能了解. 創建一個記憶體流, 包裝成密碼服務提供者, 對它做寫入/讀取.
還剩一件事, 靜態方法GetValidKeyFromString(key, l_CryptoProvider), 程式碼如下 :
public static byte[] GetValidKeyFromString(string keyString, SymmetricAlgorithm cryptoProvider)
{
// Get the string as Byte using Unicode since Unicode character is 8bit
// and also .NET support Unicode by default
byte[] l_keySeed = System.Text.Encoding.Unicode.GetBytes(keyString);
int l_seedLength = l_keySeed.Length;
int l_validKeySize = cryptoProvider.KeySize / 8;
byte[] l_validKey = new byte[l_validKeySize];
for(int index = 0; index<l_validKeySize; index++)
{
l_validKey[index] = l_keySeed[index % l_seedLength];
}
return l_validKey;
}
I assume you give a key with short or equal length as the default valid key length. If you have a key that is longer than that, you can just use it. If you are using a shorter key, This method will extend it to the valid length by repeating the key over and over again like this “IAMTHEKEYIAMTHEKEY…”. The KeySize property is the default valid key length. You may also notice that I wrap my cypher with base64, this is not necessary, I do this just in case I need to save the cypher to some text base container such as app.config.
我假設你給定的金鑰長度小於或等於預設合法金鑰長度. 如果你給的金鑰長度比較長, 那就直接用你的金鑰. 如果你的金鑰較短, 這返法就會把金鑰不斷重覆讓它增長到合法長度為止, 就好像”我是金鑰我是金鑰…”. KeySize屬性會告訴你預設合法金鑰長度. 你可以發現我用base64編碼把密件做包裝, 這不是必需的, 我這樣做只是以防我要把密件寫到文字儲存器, 例如應用程式組態.
Computer Cryptography Basic Knowledge 計算機密碼學基本知識
There are three basic types of encrypt/decrypt strategies.
Symmetric – use only one key, the secret key. Both encryption and decryption use this key. This method is fast but have key distribution problem. How do you share the key with people receiving cypher from you?
Asymmetric – Two keys involve the strategy, one public key and one private key. You spread your public key, people encrypt data with it and send the cypher back to you, you decrypt the cypher with private key. vice versa. This method is slower than symmetric one but without the key distribution problem.
Hybrid – Have the ablities of being both safe and fast by combining the above strategies. Solve the symmetric key distribution problem by encrypting the secret key with your given public key, send it back. The receiver will decrypt the secret key with his/hers private key. Then you get the speed of symmetric method by encrypting and decrypting data with secret key.
計算機理論裡有三種最基本的加密方法
對稱加密法 – 只用一把金鑰,叫秘密金鑰好了. 加密跟解密都使用這一把金鑰完成. 這個方法很快,但缺點是金鑰發佈問題. 你要怎樣安全地把金鑰送給密件收件人呢?
非對稱加密法 – 要用兩把金鑰, 一把公用金鑰和一把私有金鑰. 你把自己的公用金鑰發佈出去, 想傳資料給你的人用這金鑰加密並把密件回傳給你. 你用你的私有金鑰解密. 相反也用同樣做法. 這方法比對稱法慢但沒有金鑰發佈問題.
混合法 – 結合上面兩種方法使之既快速且安全的. 把秘密金鑰先用別人給你的公用金鑰先加密,發佈出去. 收件人再用其私有金鑰把秘密金鑰取出. 接著雙方就可以用同個秘密金鑰互送資料.