程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#編程總結(七)數據加密

C#編程總結(七)數據加密

編輯:關於C#

概述

數據加密的基本過程就是對原來為明文的文件或數據按某種算法進行處理,使其成為不可讀的一段代 碼,通常稱為“密文”,使其只能在輸入相應的密鑰之後才能顯示出本來內容,通過這樣的 途徑來達到保護數據不被非法人竊取、閱讀的目的。 該過程的逆過程為解密,即將該編碼信息轉化為其 原來數據的過程。加密建立在對信息進行數學編碼和解碼的基礎上。加密類型分為兩種,對稱加密與非 對稱加密,對稱加密雙方采用共同密鑰。非對稱加密,這種加密方式存在兩個密鑰,一個是公共密鑰( 對外公開),一種是私人密鑰(對外保密)。  

一、摘要算法

數據摘要算法是密碼學算法中非常重要的一個分支,它通過對所有數據提取指紋信息以實現數據簽名 、數據完整性校驗等功能,由於其不可逆性,有時候會被用做敏感信息的加密。數據摘要算法也被稱為 哈希(Hash)算法或散列算法。

從嚴格意義上講,摘要算法不是加密算法,但在具體應用中類似於加密算法使用,或者與加密算法一 起使用,這裡也拿來介紹下。

應用范圍:密碼加密、數據完整性校驗、數字簽名等

這裡介紹常用的兩種摘要算法,MD5與SHA1。

提示:當前MD5已經被破解,推薦使用SHA1

1、MD5

哈希函數將任意長度的二進制字符串映射為固定長度的小型二進制字符串。 加密哈希函數有這樣一 個屬性:在計算上不大可能找到散列為相同的值的兩個不同的輸入;也就是說,兩組數據的哈希值僅在 對應的數據也匹配時才會匹配。 數據的少量更改會在哈希值中產生不可預知的大量更改。MD5 算法的哈 希值大小為 128 位。

MD5 類的 ComputeHash 方法將哈希作為 16 字節的數組返回。 請注意,某些 MD5 實現會生成 32 字符的十六進制格式哈希。 若要與此類實現進行互操作,請將 ComputeHash 方法 的返回值格式化為十六進制值。

MD5加密:

/// <summary>
        /// MD5加密為32字符長度的16進制字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string EncryptByMD5(string input)
        {
            MD5 md5Hasher = MD5.Create();
            byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(input));
    
            StringBuilder sBuilder = new StringBuilder();
            //將每個字節轉為16進制
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
    
            return sBuilder.ToString();            
        }

2、SHA1

計算輸入數據的 SHA1 哈希值。

哈希值用作表示大量數據的固定大小的唯一值。 如果相應的數據也匹配,則兩個數據集的哈希應該 匹配。 數據的少量更改會在哈希值中產生不可預知的大量更改。

SHA1 算法的哈希值大小為 160 位 。

SHA1加密:

/// <summary>
        /// SHA1加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string EncryptBySHA1(string input)
        {
            SHA1 sha = new SHA1CryptoServiceProvider();          
            byte[] bytes = Encoding.Unicode.GetBytes(input);
            byte[] result = sha.ComputeHash(bytes);
            return BitConverter.ToString(result);
        }

二、對稱加密

對稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時又叫傳統密碼算法,就是加密 密鑰能夠從解密密鑰中推算出來,同時解密密鑰也可以從加密密鑰中推算出來。而在大多數的對稱算法 中,加密密鑰和解密密鑰是相同的,所以也稱這種加密算法為秘密密鑰算法或單密鑰算法。

原理圖:

優點:算法公開、計算量小、加密速度快、加密效率高。

缺點:密鑰管理困難,使用成本較高。 與公開密鑰加密算法比起來,對稱加密算法能夠提供加密和認證卻缺乏了簽名功能,使得使用范圍有所 縮小。

常用的對稱加密算法有:DES、IDEA、RC2、RC4、SKIPJACK、RC5、AES算法等

應用場景:數據傳輸、大數據量加密、敏感數據加密等等

這裡重點介紹常用的DES與AES加密算法。

提示: DES已經被破解,推薦使用3DES或AES

1、DES

最早、最著名的保密密鑰或對稱密鑰加密算法DES(Data Encryption Standard)是由IBM公司在70年代 發展起來的,並經政府的加密標准篩選後,於1976年11月被美國政府采用,DES隨後被美國國家標准局和 美國國家標准協會(American National Standard Institute,ANSI)承認。

DES使用56位密鑰對64 位的數據塊進行加密,並對64位的數據塊進行16輪編碼。與每輪編碼時,一個48位的"每輪" 密鑰值由56位的完整密鑰得出來。DES用軟件進行解碼需用很長時間,而用硬件解碼速度非常快。幸運的 是,當時大多數黑客並沒有足夠的設備制造出這種硬件設備。在1977年,人們估計要耗資兩千萬美元才 能建成一個專門計算機用於DES的解密,而且需要12個小時的破解才能得到結果。當時DES被認為是一種 十分強大的加密方法。

隨著計算機硬件的速度越來越快,制造一台這樣特殊的機器的花費已經降到了 十萬美元左右,而用它來保護十億美元的銀行,那顯然是不夠保險了。另一方面,如果只用它來保護一 台普通服務器,那麼DES確實是一種好的辦法,因為黑客絕不會僅僅為入侵一個服務器而花那麼多的錢破 解DES密文。

但是,這個算法,現在已經能夠輕易破解。不過對於日常的非機密文件同樣可以繼續使用。

加密:

/// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="input"></param>
        /// <param name="sKey"></param>
        /// <returns></returns>
        public static string EncryptString(string input, string sKey)
        {
            byte[] data = Encoding.UTF8.GetBytes(input);
            using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
            {
                des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
                des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
                ICryptoTransform desencrypt = des.CreateEncryptor();
                byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);
                return BitConverter.ToString(result);
            }            
        }

解密:

/// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="input"></param>
        /// <param name="sKey"></param>
        /// <returns></returns>
        public static string DecryptString(string input, string sKey)
        {
            string[] sInput = input.Split("-".ToCharArray());
            byte[] data = new byte[sInput.Length];
            for (int i = 0; i < sInput.Length; i++)
            {
                data[i] = byte.Parse(sInput[i], NumberStyles.HexNumber);
            }
            using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
            {
                des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
                des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
                ICryptoTransform desencrypt = des.CreateDecryptor();
                byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);
                return Encoding.UTF8.GetString(result);
            }
        }

2、AES

表示高級加密標准 (AES) 的所有實現都必須從中繼承的抽象基類。

密碼學中的高級加密標准(Advanced Encryption Standard,AES),又稱Rijndael加密法,是美國 聯邦政府采用的一種區塊加密標准。這個標准用來替代原先的DES,已經被多方分析且廣為全世界所使用 。

加密:

/// <summary>  
        /// AES加密算法  
        /// </summary>  
        /// <param name="input">明文字符串</param>  
        /// <param name="key">密鑰</param>  
        /// <returns>字符串</returns>  
        public static string EncryptByAES(string input, string key)
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32));
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = AES_IV;
    
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(input);
                        }
                        byte[] bytes = msEncrypt.ToArray();
                        //return Convert.ToBase64String(bytes);//此方法不可用
                        return BitConverter.ToString(bytes);
                    }
                }
            }
        }

解密:

/// <summary>  
        /// AES解密  
        /// </summary>  
        /// <param name="input">密文字節數組</param>  
        /// <param name="key">密鑰</param>  
        /// <returns>返回解密後的字符串</returns>  
        public static string DecryptByAES(string input, string key)
        {
            //byte[] inputBytes = Convert.FromBase64String(input); 

//Encoding.UTF8.GetBytes(input);
            string[] sInput = input.Split("-".ToCharArray());
            byte[] inputBytes = new byte[sInput.Length];
            for (int i = 0; i < sInput.Length; i++)
            {
                inputBytes[i] = byte.Parse(sInput[i], NumberStyles.HexNumber);
            }
            byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32)); 
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = keyBytes;
                aesAlg.IV = AES_IV;
    
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream(inputBytes))
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srEncrypt = new StreamReader(csEncrypt))
                        {
                            return srEncrypt.ReadToEnd();
                        }
                    }
                }
            }           
        }

查看本欄目

三、非對稱加密算法

概念:

非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私 有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對 數據進行加密,那麼只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以 這種算法叫作非對稱加密算法。 非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並 將其中的一把作為公用密鑰向其它方公開;得到該公用密鑰的乙方使用該密鑰對機密信息進行加密後再 發送給甲方;甲方再用自己保存的另一把專用密鑰對加密後的信息進行解密。另一方面,甲方可以使用 乙方的公鑰對機密信息進行簽名後再發送給乙方;乙方再用自己的私匙對數據進行驗簽。甲方只能用其 專用密鑰解密由其公用密鑰加密後的任何信息。 非對稱加密算法的保密性比較好,它消除了最終用戶交 換密鑰的需要。

原理圖:

場景1:發送者用接收者的公鑰加密,接受者用自己的私鑰解密,具體如下圖

場景2:發送者用自己的私鑰加密,接收者用發送者公布的公鑰解密,具體如下圖

場景3:數字簽名中應用,這裡暫不進行介紹,後續有相關文章進行詳細介紹。

見:http://www.cnblogs.com/yank/p/3533998.html

優點:非對稱加密體系不要求通信雙方事先傳遞密鑰或有任何約定就能完成保密 通信,並且密鑰管理方便,可實現防止假冒和抵賴,因此,更適合網絡通信中的保密通信要求

主要算法:RSA、Elgamal、背包算法、Rabin、D-H、ECC(橢圓曲線加密算法)。

1、RSA

RSA(Rivest-Shamir-Adleman)算法是基於大數不可能被質因數分解假設的公鑰體系。簡單地說就是找 兩個很大的質數。一個對外公開的為"公鑰"(Public key) ,另一個不告訴任何人,稱為 "私鑰"(Private key)。這兩個密鑰是互補的,也就是說用公鑰加密的密文可以用私鑰解密 ,反過來也一樣。

假設用戶甲要寄信給用戶乙,他們互相知道對方的公鑰。甲就用乙的公鑰加密郵件寄出,乙收到後就 可以用自己的私鑰解密出甲的原文。由於別人不知道乙的私鑰,所以即使是甲本人也無法解密那封信, 這就解決了信件保密的問題。另一方面,由於每個人都知道乙的公鑰,他們都可以給乙發信,那麼乙怎 麼確信是不是甲的來信呢?那就要用到基於加密技術的數字簽名了。

甲用自己的私鑰將簽名內容加密 ,附加在郵件後,再用乙的公鑰將整個郵件加密(注意這裡的次序,如果先加密再簽名的話,別人可以 將簽名去掉後簽上自己的簽名,從而篡改了簽名)。這樣這份密文被乙收到以後,乙用自己的私鑰將郵 件解密,得到甲的原文和數字簽名,然後用甲的公鑰解密簽名,這樣一來就可以確保兩方面的安全了。

加密:

/// <summary>
        /// RSA加密
        /// </summary>
        /// <param name="plaintext">明文</param>
        /// <param name="publicKey">公鑰</param>
        /// <returns>密文字符串</returns>
        public static string EncryptByRSA(string plaintext, string publicKey)
        {           
            UnicodeEncoding ByteConverter = new UnicodeEncoding();         
            byte[] dataToEncrypt = ByteConverter.GetBytes(plaintext);
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {
                RSA.FromXmlString(publicKey);
                byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false);
                return Convert.ToBase64String(encryptedData);
            }
        }

解密:

/// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="ciphertext">密文</param>
        /// <param name="privateKey">私鑰</param>
        /// <returns>明文字符串</returns>
        public static string DecryptByRSA(string ciphertext, string privateKey)
        {
            UnicodeEncoding byteConverter = new UnicodeEncoding();
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {
                RSA.FromXmlString(privateKey);
                byte[] encryptedData = Convert.FromBase64String(ciphertext);
                byte[] decryptedData = RSA.Decrypt(encryptedData, false);
                return byteConverter.GetString(decryptedData);
            }
        }

所有案例,見測試DEMO

源碼地址:http://files.cnblogs.com/yank/EncriptSample.zip

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved