1. 程式人生 > >計算機網路安全 —— 對稱加密演算法 DES (一)

計算機網路安全 —— 對稱加密演算法 DES (一)

一、對稱加密演算法概念

       我們通過計算機網路傳輸資料時,如果無法防止他人竊聽, 可以利用密碼學技術將傳送的資料變換成對任何不知道如何做逆變換人都不可理解的形式, 從而保證了資料的機密性。這種變換被稱為加密( encryption),被加密的資料被稱為密 文( ciphertext),而加密前的資料被稱為明文( plaintext)。 接收方必須能通過某種逆變換將密文重新變換回原來的明文,該逆變換被稱為解密( decryption)。加密和解密過程可以以一個金鑰( key)為引數,並且加密和解密過程可以公開, 而只有金鑰需要保密。 即只有知道金鑰的人才能解密密文,而任何人,即使知道加密或解密演算法也無法解密密文。

       加密金鑰和解密金鑰可以相同,也可以不同,取決於採用的是對稱金鑰密碼體制還是公開金鑰密碼體制。

       所謂對稱金鑰密碼體制是一種加密金鑰與解密金鑰相同的密碼體制。在這種加密系統中, 兩個參與者共享同一個祕密金鑰,如果用一個特定的金鑰加密一條訊息,也必須要使用相同的金鑰來解密該訊息。該系統又稱為對稱金鑰系統。

       資料加密標準( Data Encryption Standard, DES)是對稱金鑰密碼的典型代表,由IBM公司研製,於1977年被美國定為聯邦資訊標準 。其加密解密基本流程如下圖:

二、.NET 使用 DES 加密

       DES使用的金鑰為64 位( 實際金鑰長度為56 位,有8位用於奇偶校驗)。密碼的位元組長度不能低於64位(8個位元組),下面是實現程式碼:

 1     /// <summary>
 2     /// DES 加密與解密
 3     /// DES加密:https://www.zhihu.com/question/36767829
 4     /// 加密基本知識:https://www.biaodianfu.com/des.html
 5     /// </summary>
 6     public static class DesUtil
 7     {
 8         public  static Encoding Encoding { get; set; }
 9 
10         #region .ctor
11 
12         static DesUtil()
13         {
14             Encoding = Encoding.UTF8;
15         }
16         #endregion
17 
18         private  const string Key = "https://www.cnblogs.com/dongweian/";
19 
20         /// <summary>
21         /// 進行DES加密
22         /// </summary>
23         /// <param name="pToEncrypt">需要加密的字串</param>
24         /// <param name="sKey">金鑰</param>
25         /// <returns></returns>
26         public static string Encrypt(this string pToEncrypt, string sKey = Key)
27         {
28             string base64 = null;
29             using (var des = new DESCryptoServiceProvider())
30             {
31                 byte[] keys = Encoding.Default.GetBytes(sKey).Skip(0).Take(8).ToArray();
32                 byte[] inputByteArray = Encoding.GetBytes(pToEncrypt);
33                 des.Key = keys;
34                 des.IV = keys;
35                 des.Padding = PaddingMode.PKCS7;
36                 des.Mode = CipherMode.CBC;
37                 using (var ms = new MemoryStream())
38                 {
39                     using (var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
40                     {
41                         cs.Write(inputByteArray, 0, inputByteArray.Length);
42                         cs.FlushFinalBlock();
43                     } 
44                     base64 = Convert.ToBase64String(ms.ToArray());
45                 }
46                 return base64;
47             }
48         }
49 
50         /// <summary>
51         /// 進行DES解密
52         /// </summary>
53         /// <param name="pToDecrypt">需要解密的字串</param>
54         /// <param name="sKey">金鑰</param>
55         /// <returns></returns>
56         public static string Decrypt(this string pToDecrypt, string sKey = Key)
57         {
58             string returnValue = null;
59             byte[] inputByteArray = Convert.FromBase64String(pToDecrypt);
60 
61             using (var des = new DESCryptoServiceProvider())
62             {
63                 byte[] keys = Encoding.GetBytes(sKey).Skip(0).Take(8).ToArray();
64                 des.Key = keys;
65                 des.IV = keys;
66                 des.Padding = PaddingMode.PKCS7;
67                 des.Mode = CipherMode.CBC;
68                 using (var ms = new MemoryStream())
69                 {
70                     using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
71                     {
72                         cs.Write(inputByteArray, 0, inputByteArray.Length);
73                         cs.FlushFinalBlock();
74                         cs.Close();
75                     }
76                     returnValue = Encoding.GetString(ms.ToArray());
77                 }
78                 return returnValue;
79             }
80         }
81     }

二、.NET 使用 3DES 加密

       DES使用的金鑰為64 位,它是一個優秀的密碼演算法,目前還沒有發現比蠻力攻擊更好的破解方法。但隨著計算機運算速度的快速提高,56位長的金鑰已顯得太短。56位長的金鑰意味著共有256種可能的金鑰,也就是說,共約有7. 6 × 1016 種金鑰。假設一臺計算機1 µ s可執行一次DES加密,同時假定平均只需搜尋金鑰空間的一半即可找到金鑰,那麼破譯DES要超過1千年。但現在利用平行計算技術已經設計出搜尋DES金鑰的專用晶片。例如,在1999年有一批在因特網上合作的人藉助於一臺不到25萬美元的專用計算機,在略大於22h的時間就破譯了56 位金鑰的DES。

       為解決DES金鑰太短的問題,人們提出了三重DES(Triple DES, 3DES),並在1985年成為美國的一個商用加密標準[ RFC 2420]。3DES在加密時,用三個金鑰,執行三次DES演算法: 即 E運算 → D運算 → E運算。 解密時,按相反順序使用這三個金鑰,執行D運算 → E運算 → D運算。

       3DES目前正在被2001年釋出的高階加密標準( Advanced Encryption Standard, AES)所替代。AES能夠使用128位、192位和256位長的金鑰,用硬體和軟體都可以快速實現。它不需要太多記憶體,因此適用於小型移動裝置。美國國家標準與技術研究所NIST估計,如果用1s破解56位DES的計算機來破解一個128位的AES金鑰的話,要用大約149萬億年的時間才有可能。

       3DES 使用現有的DES演算法,並且當三個金鑰相同時,效果就和DES一樣。這有利於逐步推廣使用3DES。也可以僅使用兩個金鑰,即 K1= K3,相當於金鑰長度112位,這對於多數商業應用也已經足夠長了。下面程式碼我們採用192位(24個位元組)的3EDS演算法:

 1     /// <summary>
 2     /// 3DES加密與解密
 3     /// </summary>
 4     public static class TripleDesUtil
 5     {
 6         private const string Key = "https://www.cnblogs.com/dongweian/";
 7         public static Encoding Encoding { get; set; }
 8 
 9         #region .ctor
10 
11         static TripleDesUtil()
12         {
13             Encoding = Encoding.UTF8;
14         }
15         #endregion
16 
17 
18         /// <summary>
19         /// 進行3DES加密
20         /// </summary>
21         /// <param name="pToEncrypt">需要加密的字串</param>
22         /// <param name="sKey">金鑰(用於3DES演算法的金鑰。金鑰大小必須為192位)</param>
23         /// <returns></returns>
24         public static string Encrypt(this string pToEncrypt, string sKey = Key)
25         {
26             string base64 = null;
27             using (var des = new TripleDESCng())
28             {
29                 byte[] keys = Encoding.GetBytes(sKey);
30                 byte[] inputByteArray = Encoding.GetBytes(pToEncrypt);
31                 des.Key = keys.Skip(0).Take(24).ToArray();
32                 des.IV = keys.Skip(0).Take(8).ToArray();
33                 des.Padding = PaddingMode.PKCS7;
34                 des.Mode = CipherMode.CBC;
35                 using (var ms = new MemoryStream())
36                 {
37                     using (var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
38                     {
39                         cs.Write(inputByteArray, 0, inputByteArray.Length);
40                         cs.FlushFinalBlock();
41                     }
42                     base64 = Convert.ToBase64String(ms.ToArray());
43                 }
44                 return base64;
45             }
46         }
47 
48         /// <summary>
49         /// 進行3DES解密
50         /// </summary>
51         /// <param name="pToDecrypt">需要解密的字串</param>
52         /// <param name="sKey">金鑰</param>
53         /// <returns></returns>
54         public static string Decrypt(this string pToDecrypt, string sKey = Key)
55         {
56             string returnValue = null;
57             byte[] inputByteArray = Convert.FromBase64String(pToDecrypt);
58 
59             using (var des = new TripleDESCng())
60             {
61                 byte[] keys = Encoding.GetBytes(sKey);
62                 des.Key = keys.Skip(0).Take(24).ToArray();
63                 des.IV = keys.Skip(0).Take(8).ToArray();
64                 des.Padding = PaddingMode.PKCS7;
65                 des.Mode = CipherMode.CBC;
66                 using (var ms = new MemoryStream())
67                 {
68                     using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
69                     {
70                         cs.Write(inputByteArray, 0, inputByteArray.Length);
71                         cs.FlushFinalBlock();
72                         cs.Close();
73                     }
74                     returnValue = Encoding.GetString(ms.ToArray());
75                 }
76                 return returnValue;
77             }
78         }
79     }

 三、測試程式碼與效果

 1        static void Main(string[] args)
 2        {
 3             string key = "https://www.cnblogs.com/dongweian/";
 4             Console.Write($"請輸入內容:");
 5             string input = Console.ReadLine();
 6             var encrypt = TripleDesUtil.Encrypt(input, key);
 7             Console.WriteLine($"DES加密後內容:{encrypt}");
 8             Console.WriteLine($"DES解密後內容:{TripleDesUtil.Decrypt(encrypt, key)}");
 9 
10             var encrypt3 = TripleDesUtil.Encrypt(input, key);
11             Console.WriteLine($"3DES加密後內容:{encrypt3}");
12             Console.WriteLine($"3EDS解密後內容:{TripleDesUtil.Decrypt(encrypt3, key)}");
13             Console.ReadKey();
14         }

&n