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

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

    數據加密技術是網絡中最基本的安全技術,主要是經過對網絡中傳輸的信息進行數據加密來保障其安全性,這是一種主動安全防護策略,用很小的代價算法

便可爲信息提供至關大的安全保護。數組

    1、加密的基本概念緩存

    "加密",是一種限制對網絡上傳輸數據的訪問權的技術。原始數據(也稱爲明文,plaintext)被加密設備(硬件或軟件)和密鑰加密而產生的通過編碼的數據安全

稱爲密文(ciphertext)。將密文還原爲原始明文的過程稱爲解密,它是加密的反向處理,但解密者必須利用相同類型的加密設備和密鑰對密文進行解密。服務器

    加密的基本功能包括:網絡

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

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

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

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

    數據加密是確保計算機網絡安全的一種重要機制,雖然因爲成本、技術和管理上的複雜性等緣由,目前還沒有在網絡中普及,但數據加密的確是實現分佈

式系統和網絡環境下數據安全的重要手段之一。

    數據加密可在網絡OSI七層協議(OSI是Open System Interconnect的縮寫,意爲開放式系統互聯。國際標準組織(國際標準化組織)制定了OSI模型。這

個模型把網絡通訊的工做分爲7層,分別是物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。)的多層上實現,因此從加密技術應用的邏

輯位置看,有三種方式:

    1)鏈路加密:一般把網絡層如下的加密叫鏈路加密,主要用於保護通訊節點間傳輸的數據,加解密由置於線路上的密碼設備實現。根據傳遞的數據的同

步方式又可分爲同步通訊加密和異步通訊加密兩種,同步通訊加密又包含字節同步通訊加密和位同步通訊加密。

    2)節點加密:是對鏈路加密的改進。在協議傳輸層上進行加密,主要是對源節點和目標節點之間傳輸數據進行加密保護,與鏈路加密相似,只是加密算

法要結合在依附於節點的加密模件中,克服了鏈路加密在節點處易遭非法存取的缺點。

    3)端對端加密:網絡層以上的加密稱爲端對端加密,是面向網絡層主體。對應用層的數據信息進行加密,易於用軟件實現,且成本低,但密鑰管理問題

困難,主要適合大型網絡系統中信息在多個發方和收方之間傳輸的狀況。

    2、數據加密的應用

    1)媒體加密:DRM

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

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

    4)硬件加密:加密狗

    3、加密技術發展趨勢

    1)私用密鑰加密技術與公開密鑰加密技術相結合:鑑於兩種密碼體制加密的特色,在實際應用中能夠採用折衷方案,即結合使用DES/IDEA和RSA,以

DES爲"內核",RSA爲"外殼",對於網絡中傳輸的數據可用DES或IDEA加密,而加密用的密鑰則用RSA加密傳送,此種方法既保證了數據安全又提升了加密

和解密的速度,這也是目前加密技術發展的新方向之一。

    2)尋求新算法:跳出以常見的迭代爲基礎的構造思路,脫離基於某些數學問題複雜性的構造方法。如劉尊全先生提出的劉氏算法,是一種基於密鑰的公

開密鑰體制。它採用隨機性原理構造加解密變換,並將其所有運算控制隱匿於密鑰中,密鑰長度可變;它採用選取必定長度的分割來構造大的搜索空間,從

而實現一次非線性變換。此種加密算法加密強度高、速度快、計算開銷低。

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

主板上。

    4、加密技術的分類

    加密類型能夠簡單地分爲四種:

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

    2)私用密鑰加密技術--對稱式加密(Symmetric Key Encryption):對稱式加密方式對加密和解密使用相同的密鑰。一般,這種加密方式在應用中難以實

施,由於用同一種安全方式共享密鑰很難,如:RC四、RC二、DES和AES系列加密算法。

    3)公開密鑰加密技術--非對稱密鑰加密(Asymmetric Key Encryption):非對稱密鑰加密使用一組公共/私人密鑰系統,加密時使用一種密鑰,解密時使

用另外一種密鑰。公共密鑰能夠普遍的共享和透露,當須要用加密方式向服務器外部傳送數據時,這種加密方式更方便,如: RSA。

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

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

    5.1對稱加密簡述

    對稱加密,是一種比較傳統的加密方式,其加密運算、解密運算使用的是一樣的密鑰,信息的發送者和信息的接收者在進行信息的傳輸與處理時,必須共

同持有該密碼(稱爲對稱密碼)。所以,通訊雙方都必須得到這把鑰匙,並保持鑰匙的祕密。

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

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

    第2、加密方法的安全性依賴於密鑰的祕密性,而不是算法的祕密性,所以,咱們沒有必要確保算法的祕密性(事實上,現實中使用的不少單鑰密碼系統

的算法都是公開的),可是咱們必定要保證密鑰的祕密性。

    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

    運行結果以下:

    6、非對稱加密之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、e一、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

    運行結果以下:

相關文章
相關標籤/搜索