C#加密與解密(DES\RSA)學習筆記


    本筆記摘抄自:https://www.cnblogs.com/skylaugh/archive/2011/07/12/2103572.html,記錄一下學習過程以備后續查用。

    數據加密技術是網絡中最基本的安全技術,主要是通過對網絡中傳輸的信息進行數據加密來保障其安全性,這是一種主動安全防御策略,用很小的代價即可為信息提供相當大的安全保護。

    一、加密的基本概念

    "加密",是一種限制對網絡上傳輸數據的訪問權的技術。原始數據(也稱為明文,plaintext)被加密設備(硬件或軟件)和密鑰加密而產生的經過編碼的數據稱為密文(ciphertext)。將密文還原為原始明文的過程稱為解密,它是加密的反向處理,但解密者必須利用相同類型的加密設備和密鑰對密文進行解密。

    加密的基本功能包括:

    1)防止不速之客查看機密的數據文件。

    2)防止機密數據被泄露或篡改。

    3)防止特權用戶(如系統管理員)查看私人數據文件。

    4)使入侵者不能輕易地查找一個系統的文件。

    數據加密是確保計算機網絡安全的一種重要機制,雖然由於成本、技術和管理上的復雜性等原因,目前尚未在網絡中普及,但數據加密的確是實現分布式系統和網絡環境下數據安全的重要手段之一。

    數據加密可在網絡OSI七層協議(OSI是Open System Interconnect的縮寫,意為開放式系統互聯。國際標准組織(國際標准化組織)制定了OSI模型。這個模型把網絡通信的工作分為7層,分別是物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。)的多層上實現,所以從加密技術應用的邏輯位置看,有三種方式:

    1)鏈路加密:通常把網絡層以下的加密叫鏈路加密,主要用於保護通信節點間傳輸的數據,加解密由置於線路上的密碼設備實現。根據傳遞的數據的同步方式又可分為同步通信加密和異步通信加密兩種,同步通信加密又包含字節同步通信加密和位同步通信加密。

    2)節點加密:是對鏈路加密的改進。在協議傳輸層上進行加密,主要是對源節點和目標節點之間傳輸數據進行加密保護,與鏈路加密類似,只是加密算法要結合在依附於節點的加密模件中,克服了鏈路加密在節點處易遭非法存取的缺點。

    3)端對端加密:網絡層以上的加密稱為端對端加密,是面向網絡層主體。對應用層的數據信息進行加密,易於用軟件實現,且成本低,但密鑰管理問題困難,主要適合大型網絡系統中信息在多個發方和收方之間傳輸的情況。

    二、數據加密的應用

    1)媒體加密:DRM

    2)文件加密:文本加密、pdf、word

    3)數據加密:C#中的數據加密

    4)硬件加密:加密狗

    三、加密技術發展趨勢

    1)私用密鑰加密技術與公開密鑰加密技術相結合:鑒於兩種密碼體制加密的特點,在實際應用中可以采用折衷方案,即結合使用DES/IDEA和RSA,以DES為"內核",RSA為"外殼",對於網絡中傳輸的數據可用DES或IDEA加密,而加密用的密鑰則用RSA加密傳送,此種方法既保證了數據安全又提高了加密和解密的速度,這也是目前加密技術發展的新方向之一。

    2)尋求新算法:跳出以常見的迭代為基礎的構造思路,脫離基於某些數學問題復雜性的構造方法。如劉尊全先生提出的劉氏算法,是一種基於密鑰的公開密鑰體制。它采用隨機性原理構造加解密變換,並將其全部運算控制隱匿於密鑰中,密鑰長度可變;它采用選取一定長度的分割來構造大的搜索空間,從而實現一次非線性變換。此種加密算法加密強度高、速度快、計算開銷低。

    3)加密最終將被集成到系統和網絡中,例如IPV6協議就已有了內置加密的支持,在硬件方面,Intel公司正研制一種加密協處理器,它可以集成到微機的主板上。

    四、加密技術的分類

    加密類型可以簡單地分為四種:

    1)根本不考慮解密問題。

    2)私用密鑰加密技術--對稱式加密(Symmetric Key Encryption):對稱式加密方式對加密和解密使用相同的密鑰。通常,這種加密方式在應用中難以實施,因為用同一種安全方式共享密鑰很難,如:RC4、RC2、DES和AES系列加密算法。

    3)公開密鑰加密技術--非對稱密鑰加密(Asymmetric Key Encryption):非對稱密鑰加密使用一組公共/私人密鑰系統,加密時使用一種密鑰,解密時使用另一種密鑰。公共密鑰可以廣泛的共享和透露,當需要用加密方式向服務器外部傳送數據時,這種加密方式更方便,如: RSA。

    4)數字證書(Certificate):數字證書是一種非對稱密鑰加密,但是,一個組織可以使用證書並通過數字簽名將一組公鑰和私鑰與其擁有者相關聯。

    五、對稱加密之DES加密與解密

    5.1對稱加密簡述

    對稱加密,是一種比較傳統的加密方式,其加密運算、解密運算使用的是同樣的密鑰,信息的發送者和信息的接收者在進行信息的傳輸與處理時,必須共同持有該密碼(稱為對稱密碼)。因此,通信雙方都必須獲得這把鑰匙,並保持鑰匙的秘密。

    單鑰密碼系統的安全性依賴於以下兩個因素:

    第一、加密算法必須是足夠強,僅僅基於密文本身去解密信息在實踐上是不可能的。

    第二、加密方法的安全性依賴於密鑰的秘密性,而不是算法的秘密性,因此,我們沒有必要確保算法的秘密性(事實上,現實中使用的很多單鑰密碼系統的算法都是公開的),但是我們一定要保證密鑰的秘密性。

    DES(Data Encryption Standard)和TripleDES是對稱加密的兩種實現:

    1)DES和TripleDES基本算法一致,只是TripleDES算法提供的key位數更多,加密可靠性更高。

    2)DES使用的密鑰key為8字節,初始向量IV也是8字節。

    3)TripleDES的密鑰key為24字節,初始向量IV也是8字節。

    4)兩種算法都是以8字節為一個塊進行加密,一個數據塊一個數據塊的加密,一個8字節的明文加密后的密文也是8字節。如果明文長度不為8字節的整數倍,添加值為0的字節湊滿8字節整數倍,所以加密后的密文長度一定為8字節的整數倍。

    5.2加密解密過程

    上圖是整個DES和TripleDES算法的加密解密過程,下面以TripleDES為例,結合dotnet分析加密解密的各個步驟,並給出相關實現代碼。

    5.2.1生成Key和IV

    System.Security.Cryptography.TripleDESCryptoServiceProvider類是.NET中實現TripleDES算法的主要類。

    TripleDESCryptoServiceProvider類只有一個構造方法TripleDESCryptoServiceProvider(),這個方法把一些屬性初始化:

    KeySize(加密密鑰長度,以位為單位)= 192(24字節)

    BlockSize(加密處理的數據塊大小,以位為單位)= 64(8字節)

    FeedbackSize(加密數據塊后返回的數據大小,以位為單位)= 64(8字節)

    TripleDESCryptoServiceProvider構造方法同時會初始化一組隨機的Key和IV。

    默認的TripleDESCryptoServiceProvider的Key為24字節,IV為8字節,加密數據塊為8字節。

    生成Key和IV的代碼很簡單:

TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
byte[] keyArray = tripleDES.Key;
byte[] ivArray = tripleDES.IV;

    5.2.2字符串明文轉成編碼字節流

    待加密的數據可能有兩種形式:一種是二進制的數據,本身就是一組字節流,這樣的數據可以跳過這一步,直接進入加密步驟;還有一種情況是字符串數據,字符串中同樣的字符使用不同的編碼會生成不同的字節碼,所以從字符串到字節流的轉換是需要指定使用的編碼。在解密之后,要從字節流轉換到字符串就要使用相同的編碼解碼,否則會出現亂碼。

//待加密的字符串
string plainTextString = "Here is some data to encrypt.";
//使用utf-8編碼(也可以使用其它的編碼)
Encoding encoding = Encoding.GetEncoding("utf-8");
//把字符串明文轉換成utf-8編碼的字節流
byte[] plainTextArray = encoding.GetBytes(plainTextString);

    5.2.3加密操作

    加密的原料是明文字節流,TripleDES算法對字節流進行加密,返回的是加密后的字節流,同時要給定加密使用的Key和IV。

    /// <summary>
    /// 加密解密幫助類
    /// </summary>
    public static class CryptoHelper
    {
        /// <summary>
        /// 對稱加密之TripleDes加密
        /// </summary>
        /// <param name="plainTextArray">明文字節數組</param>
        /// <param name="Key">Key</param>
        /// <param name="IV">IV</param>
        /// <returns>返回字節數組</returns>
        public static byte[] TripleDesEncrypt(string plainText, byte[] Key, byte[] IV)
        {
            //將明文字符串轉成明文字節數組
            Encoding encoding = Encoding.GetEncoding("utf-8");
            byte[] plainTextArray = encoding.GetBytes(plainText);

            //新建一個MemoryStream對象存放加密后的數據流
            MemoryStream memoryStream = new MemoryStream();

            //新建一個CryptoStream對象
            CryptoStream cryptoStream = new CryptoStream
                (
                    memoryStream,
                    new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
                    CryptoStreamMode.Write
                );

            //將加密后的字節流寫入到memoryStream
            cryptoStream.Write(plainTextArray, 0, plainTextArray.Length);

            //把緩沖區中的最后狀態更新到memoryStream,並清除cryptoStream的緩存區。
            cryptoStream.FlushFinalBlock();

            //把加密后的數據流轉成字節流
            byte[] result = memoryStream.ToArray();

            //關閉兩個Stream
            cryptoStream.Close();
            memoryStream.Close();

            //返回結果
            return result;
        }
    }
View Code

    5.2.4解密操作

    解密5.2.3生成的密文byte[],需要使用到加密步驟使用的同一組Key和IV。

    /// <summary>
    /// 加密解密幫助類
    /// </summary>
    public static class CryptoHelper
    {
        /// <summary>
        /// 對稱加密之TripleDes解密
        /// </summary>
        /// <param name="encryptTextArray">加密字節數組</param>
        /// <param name="Key">Key</param>
        /// <param name="IV">IV</param>
        /// <returns>返回字符串</returns>
        public static string TripleDesDecrypt(byte[] encryptTextArray, byte[] Key, byte[] IV)
        {
            //將加密字符串轉成加密字節數組
            Encoding encoding = Encoding.GetEncoding("utf-8");

            //新建一個MemoryStream對象存放解密后的數據流
            MemoryStream memoryStream = new MemoryStream(encryptTextArray);

            //新建一個CryptoStream對象
            CryptoStream cryptoStream = new CryptoStream
                (
                    memoryStream,
                    new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV),
                    CryptoStreamMode.Read
                );

            //新建一個存放解密后的明文字節數組(可能比加密前的明文長)
            byte[] decryptTextArray = new byte[encryptTextArray.Length];

            //把解密后的數據流讀到
            cryptoStream.Read(decryptTextArray, 0, decryptTextArray.Length);

            //關閉兩個Stream
            memoryStream.Close();
            cryptoStream.Close();

            return encoding.GetString(decryptTextArray);
        }
    }
View Code

    有一點需要注意,DES加密是以數據塊為單位加密的,8個字節一個數據塊。如果待加密明文byte[]的長度不是8字節的整數倍,算法先用值為“0”的byte補足8個字節,然后再進行加密,所以加密后的密文長度一定是8的整數倍。這樣的密文解密后如果補了0值的byte,則解密后這些0值的byte依然存在。

    5.2.5示例

    class Program
    {
        static void Main(string[] args)
        {
            #region 對稱加密之TripleDes加密與解密
            //明文數據
            string plainText = "人生如戲,全靠演技。";

            //生成Key和IV
            TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
            byte[] keyArray = tripleDES.Key;
            byte[] ivArray = tripleDES.IV;

            //加密
            byte[] encryptTextArray = CryptoHelper.TripleDesEncrypt(plainText, keyArray, ivArray);

            //解密
            string decryptText = CryptoHelper.TripleDesDecrypt(encryptTextArray, keyArray, ivArray);

            //輸出
            Console.WriteLine($"明文數據:{plainText}");
            Console.WriteLine($"解密后數據:{decryptText}");
            Console.Read();
            #endregion
        }
    }
View Code

    運行結果如下:

    六、非對稱加密之RSA加密和解密的講解

    RSA公鑰加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者的名字。RSA是目前最有影響力的公鑰加密算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數據加密標准;RSA算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但是想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰;RSA算法是第一個能同時用於加密和數字簽名的算法,也易於理解和操作。

    RSA算法是被研究得最廣泛的公鑰算法,從提出到現在已近二十年,經歷了各種攻擊的考驗,逐漸為人們所接受,被普遍認為是目前最優秀的公鑰方案之一。RSA的安全性依賴於大數的因子分解,但並沒有從理論上證明破譯RSA的難度與大數分解難度等價,即RSA的重大缺陷是無法從理論上把握它的保密性能如何,而且密碼學界多數人士傾向於因子分解不是NPC問題。

    RSA的缺點主要有:

    1)產生密鑰很麻煩,受到素數產生技術的限制,因而難以做到一次一密。

    2)分組長度太大,為保證安全性,n至少也要600bits以上,導致運算代價很高,尤其是速度較慢(較對稱密碼算法慢幾個數量級),且隨着大數分解技術的發展,這個長度還在增加,不利於數據格式的標准化。目前,SET(Secure Electronic Transaction)協議中要求CA采用2048bits長的密鑰,其它實體使用1024比特的密鑰。

    3)RSA密鑰長度隨着保密級別提高,增加很快。

    下表列出了對同一安全級別所對應的密鑰長度:

保密級別

對稱密鑰長度(bit)

RSA密鑰長度(bit)

ECC密鑰長度(bit)

保密年限

80

80

1024

160

2010

112

112

2048

224

2030

128

128

3072

256

2040

192

192

7680

384

2080

256

256

15360

512

2120

    RSA算法是一種非對稱密碼算法,所謂非對稱,就是指該算法需要一對密鑰,使用其中一個加密,則需要用另一個才能解密。

    RSA的算法涉及三個參數n、e1、e2:

    1)n是兩個大質數p、q的積,n的二進制表示時所占用的位數,就是所謂的密鑰長度。

    2)e1和e2是一對相關的值,e1可以任意取,但要求e1與(p-1)*(q-1)互質,再選擇e2,要求(e2*e1)mod((p-1)*(q-1))=1。

    3)(n及e1)、(n及e2)就是密鑰對。

    RSA加解密的算法完全相同,設A為明文,B為密文,則:A=B^e1 mod n;B=A^e2 mod n;

    e1和e2可以互換使用,即:A=B^e2 mod n;B=A^e1 mod n;

    6.1生成一對公鑰和密鑰

    /// <summary>
    /// 加密解密幫助類
    /// </summary>
    public static class CryptoHelper
    {
        /// <summary>
        /// 非對稱加密之RSA產生公鑰密鑰
        /// </summary>
        public static void RSACreateKey()
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            //公鑰
            using (StreamWriter writer = new StreamWriter(@"..\..\PublicKey.xml"))
            {
                writer.WriteLine(rsa.ToXmlString(false));
            }
            //密鑰(請注意保密)
            using (StreamWriter writer = new StreamWriter(@"..\..\PrivateKey.xml"))
            {
                writer.WriteLine(rsa.ToXmlString(true));
            }
        }
    }
View Code

    6.2加密操作

    /// <summary>
    /// 加密解密幫助類
    /// </summary>
    public static class CryptoHelper
    {
        /// <summary>
        /// 非對稱加密之RSA加密
        /// </summary>
        /// <param name="publickey">公鑰</param>
        /// <param name="plainText">明文字符串</param>
        /// <returns>加密字符串</returns>
        public static string RSAEncrypt(string publickey, string plainText)
        {
            StreamReader reader = new StreamReader(@"..\..\PublicKey.xml", Encoding.UTF8);
            publickey = reader.ReadToEnd();
            reader.Close();

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(publickey);
            byte[] cipherBytes = rsa.Encrypt(Encoding.UTF8.GetBytes(plainText), false);

            return Convert.ToBase64String(cipherBytes);
        }
    }
View Code

    6.3解密操作

    /// <summary>
    /// 加密解密幫助類
    /// </summary>
    public static class CryptoHelper
    {
        /// <summary>
        /// 非對稱加密之RSA解密
        /// </summary>
        /// <param name="privatekey">密鑰</param>
        /// <param name="encryptText">加密字符串</param>
        /// <returns>解密字符串</returns>
        public static string RSADecrypt(string privatekey, string encryptText)
        {
            StreamReader reader = new StreamReader(@"..\..\PrivateKey.xml", Encoding.UTF8);
            privatekey = reader.ReadToEnd();
            reader.Close();

            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(privatekey);
            byte[] cipherBytes = rsa.Decrypt(Convert.FromBase64String(encryptText), false);

            return Encoding.UTF8.GetString(cipherBytes);
        }
    }
View Code

    6.4示例

    class Program
    {
        static void Main(string[] args)
        {
            #region 非對稱加密之RSA加密與解密
            //明文數據
            string plainText = "人生如戲,全靠演技。";

            //生成公鑰和密鑰
            CryptoHelper.RSACreateKey();

            //加密
            string encryptText = CryptoHelper.RSAEncrypt("", plainText);

            //解密
            string decryptText = CryptoHelper.RSADecrypt("", encryptText);

            Console.WriteLine($"明文數據:{plainText}\n");
            Console.WriteLine($"加密后數據:{encryptText}\n");
            Console.WriteLine($"解密后數據:{decryptText}");
            Console.Read();
            #endregion
        }
    }
View Code

    運行結果如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM