加密解密概述及.NET中對加密解密的支援(二)

來源:互聯網
上載者:User

 

.NET中加密解密的支援

相信通過前面幾頁的敘述,大家已經明白了加密解密、數位簽章的基本原理,下面我們看一下在.NET中是如何來支援加密解密的。正如上面我們所進行的分類,.NET中也提供了兩組類用於加密解密,一組為對稱式加密,一組為非對稱式加密。這些類按照名稱還可以分為兩組,一組尾碼為“CryptoServiceProvider”的,是對於底層Windows API的封裝類,一組尾碼為“Managed”,是在.NET中全新編寫的類。

.NET對稱式加密解密支援

.NET Framework提供了一些常見的對稱演算法的實現,包括DES、RC2等。下面列出了與對稱演算法有關的類的結構:

  System.Security.Cryptography.SymmetricAlgorithm

  System.Security.Cryptography.Aes
     System.Security.Cryptography.AesCryptoServiceProvider
     System.Security.Cryptography.AesManaged
     System.Security.Cryptography.DES

      System.Security.Cryptography.DESCryptoServiceProvider
     System.Security.Cryptography.RC2

     System.Security.Cryptography.RC2CryptoServiceProvider
     System.Security.Cryptography.Rijndael

     System.Security.Cryptography.RijndaelManaged
     System.Security.Cryptography.TripleDES

     System.Security.Cryptography.TripleDESCryptoServiceProvider

這些類中黑體表示的類為實現演算法的具體類,其它的都是抽象類別;也可以根據需要實現自己的對稱演算法。

.NET非對稱式加密解密支援

RSA是當今最常用的非對稱演算法,其被應用於很多領域。RSA演算法的理論依據來自於一個大素數所具有的特性:對於給定的兩個大素數A與B,很容易計算出它們的乘積;但是,僅知道AB的成績卻很難計算原來的A與B各自的值。

.NET Frameork提供了兩個類供我們使用RSA演算法:用於加密資料的RSACryptoServiceProvider類以及用於對資料做數位簽章的DSACryptoServiceProvider類(DSA: Digital Signature Algorithm,數位簽章演算法),其類的階層如下

 

  System.Security.Cryptography.AsymmetricAlgorithm
     System.Security.Cryptography.DSA

      System.Security.Cryptography.DSACryptoServiceProvider
     System.Security.Cryptography.RSA

      System.Security.Cryptography.RSACryptoServiceProvider

   System.Security.Cryptography.ECDiffieHellman(橢圓曲線Diffie-Hellman (ECDH) 演算法實現)

      System.Security.Cryptography.ECDiffieHellmanCng(橢圓曲線Diffie-Hellman (ECDH) 演算法的新一代密碼編譯 (CNG) 實現)
   System.Security.Cryptography.ECDsa

     System.Security.Cryptography.ECDsaCng(橢圓曲線數位簽章演算法 (ECDSA) 的新一代密碼編譯 (CNG) 實現)

 

.NET散列演算法支援

散列演算法是把長長的一列資料變成較短的代碼,這是最流行的64位散列密鑰。兩個最流行的散列演算法是SHA(Secured Hash Algorithm)和MD5(MessageDigest version5)。這些散列密鑰用於標記數字文檔。

    散列值是根據一個資料集合計算出來的數字。如果資料集合不同,那麼計算出來的數字基本上也是不同的。.NET Framework在其System.Security.Cryptography命名空間下提供了一些主要的散列演算法,包括:SHAx、RIPEMD160、與MD5。

 

  System.Security.Cryptography.HashAlgorithm

System.Security.Cryptography.KeyedHashAlgorithm(鍵控雜湊演算法的實現基類)

             System.Security.Cryptography.HMAC (基於雜湊的訊息驗證碼 (HMAC)的抽象類別)

System.Security.Cryptography.HMACMD5

System.Security.Cryptography.HMACRIPEMD160

System.Security.Cryptography.HMACSHA1

System.Security.Cryptography.HMACSHA256

System.Security.Cryptography.HMACSHA384

System.Security.Cryptography.HMACSHA512

System.Security.Cryptography.MACTripleDES
System.Security.Cryptography.MD5

System.Security.Cryptography.MD5Cng(128 位雜湊演算法的 CNG(新一代密碼編譯)實現

        System.Security.Cryptography.MD5CryptoServiceProvider

System.Security.Cryptography.RIPEMD160

        System.Security.Cryptography.RIPEMD160Managed

System.Security.Cryptography.SHA1

          System.Security.Cryptography.SHA1CryptoServiceProvider
           System.Security.Cryptography.SHA1Managed

System.Security.Cryptography.SHA256

   System.Security.Cryptography.SHA256Managed

System.Security.Cryptography.SHA384

        System.Security.Cryptography.SHA384Managed

System.Security.Cryptography.SHA512

        System.Security.Cryptography.SHA512Managed

 

KeyedHash

鍵控雜湊演算法是依賴於密鑰的單向雜湊函數,用作訊息驗證碼。只有知道密鑰的人才能驗證雜湊值。加密雜湊演算法提供沒有機密的真實性。

SHA

SHA(安全散列演算法)是一個塊密碼,在64位的資料區塊上執行,這個演算法的改進版本採用了更大的密鑰值,當然,密鑰值越大所需的計算時間越長。而且,對於相對較小的檔案,散列值越小就越安全,就是說,散列演算法的塊大小應小於或等於資料區塊本身的大小。 SHA1演算法的散列範圍是160位。

.NET Framework也提供了更大的密鑰值演算法,分別為SHA256、SHA384和SHA512。名稱最後的數字表示其塊大小。

ASP.NET安全性中的成員資格提供者使用SHA1加密使用者密碼。

MD5

MD5表示MessageDigest版本5。它是一個加密的單向散列演算法。MD5有抗偽造,計算成本低且執行簡單等特點。現在MD5已成為散列演算法的事實標準。

    .NET Framework提供了MD5CryptoServiceProvider這個類實現MD5演算法。該類與SHA1共用同一個基類,前面的樣本也只需要做簡單的改動即可成為使用MD5進行處理的例子。

RIPEMD-160

基於MD5的RIPEMD-160最早出現於歐洲,是一個使用160位的散列演算法。.NET也引入了對這種演算法的支援。

 

對稱式加密解密樣本

現在假設我們以TripleDES作為演算法,那麼加密的流程如下:

1. 先建立一個TripleDESCryptoServiceProvider的執行個體,執行個體名比如叫provider。

2.在provider上指定密鑰和IV,也就是它的Key屬性和IV屬性。這裡簡單解釋一下IV(initialization vector),如果一個字串(或者資料)加密之前很多部分是重複的比如ABCABCABC,那麼加密之後儘管字串是亂碼,但相關部分也是重複的。為瞭解決這個問題,就引入了IV,當使用它以後,加密之後即使是重複的也被打亂了。對於特定演算法,密鑰和IV的值可以隨意指定,但長度是固定,通常密鑰為128位或196位,IV為64位。密鑰和IV都是byte[]類型,因此,如果使用Encoding類來將字串轉換為byte[],那麼編碼方式就很重要,因為UTF8是變長編碼,所以對於中文和英文,需要特別注意byte[]的長度問題。

3.如果是加密,在provider上調用CreateEncryptor()方法,建立一個ICryptoTransform類型的加密器對象;如果是解密,在provider上調用CreateDecryptor()方法,同樣是建立一個ICryptoTransform類型的解密器對象。ICryptoTransform定義了加密轉換的運算,.NET將在底層調用這個介面。

4.因為流和byte[]是資料類型無關的一種資料結構,可以儲存和傳輸任何形式的資料,區別只是byte[]是一個靜態概念而流是一個動態概念。因此,.NET採用了流的方式進行加密和解密,我們可以想到有兩個流,一個是明文流,含有加密前的資料;一個是密文流,含有加密後的資料。那麼就必然有一個中介者,將明文流轉換為密文流;或者將密文流轉換為明文流。.NET中執行這個操作的中介者也是一個流類型,叫做CryptoStream。它的建構函式如下,共有三個參數:

publicCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)

5. 當加密時,stream為密文流(注意此時密文流還沒有包含資料,僅僅是一個空流);ICryptoTransform是第3步建立的加密器,包含著加密的演算法;CryptoStreamMode枚舉為Write,意思是將流經CryptoStream的明文流寫入到密文流中。最後,從密文流中獲得加密後的資料。

6. 當解密時,stream為密文流(此時密文流含有資料);ICryptoTransform是第3步建立的解密器,包含著解密的演算法;CryptoStreamMode枚舉為Read,意思是將密文流中的資料讀出到byte[]數組中,進而再由byte[]轉換為明文流、明文字串。

可見,CryptoStream總是接受密文流,並且根據CryptoStreamMode枚舉的值來決定是將明文流寫入到密文流(加密),還是將密文流讀入到明文流中(解密)。下面是我編寫的一個加密解密的Helper類:

// 對稱式加密協助類    public class CryptoHelper    {        private SymmetricAlgorithm provider;        private ICryptoTransform encryptor;        private ICryptoTransform decryptor;        private const int BufferSize = 1024;        public CryptoHelper(string algorithmName)        {            provider = SymmetricAlgorithm.Create(algorithmName);            string strKey = ConfigurationManager.AppSettings["CryptoKey"];            string strIV = ConfigurationManager.AppSettings["CryptoIV"];            if (string.IsNullOrEmpty(strKey) || string.IsNullOrEmpty(strIV))                throw new ArgumentNullException("CryptoKey");            //Key            byte[] bsKey = Encoding.UTF8.GetBytes(strKey);            int keySize = provider.KeySize/8;            if (bsKey.Length != keySize)            {                byte[] key = new byte[keySize];                if (bsKey.Length > keySize)                    Array.Copy(bsKey, key, keySize);                else                    Array.Copy(bsKey, key, bsKey.Length);                provider.Key = key;            }            else            {                provider.Key = bsKey;            }            //IV            byte[] bsIV = Encoding.UTF8.GetBytes(strIV);            int ivSize = provider.BlockSize / 8;            if (bsIV.Length != ivSize)            {                byte[] iv = new byte[ivSize];                if(bsIV.Length > ivSize)                    Array.Copy(bsIV, iv, ivSize);                else                    Array.Copy(bsIV, iv, bsIV.Length);                provider.IV = iv;            }            else            {                provider.IV = bsIV;            }            encryptor = provider.CreateEncryptor();            decryptor = provider.CreateDecryptor();        }        public CryptoHelper() : this("TripleDES") { }        // Encrypt        public string Encrypt(string clearText)        {            byte[] clearBuffer = Encoding.UTF8.GetBytes(clearText);            MemoryStream clearStream = null;            MemoryStream encryptedStream = null;            CryptoStream cryptoStream = null;            try            {                clearStream = new MemoryStream(clearBuffer);                encryptedStream = new MemoryStream();                cryptoStream = new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write);                byte[] buffer = new byte[BufferSize];                int bytesRead = 0;                while((bytesRead = clearStream.Read(buffer, 0, BufferSize)) > 0)                {                    cryptoStream.Write(buffer, 0, bytesRead);                }                cryptoStream.FlushFinalBlock();                buffer = encryptedStream.ToArray();                string encryptedText = Convert.ToBase64String(buffer);                return encryptedText;            }            finally            {                if (cryptoStream != null)                {                    cryptoStream.Close();                    cryptoStream = null;                }                if (encryptedStream != null)                {                    encryptedStream.Close();                    encryptedStream = null;                }                if (clearStream != null)                {                    clearStream.Close();                    clearStream = null;                }                if (provider != null)                {                    provider.Clear();                }            }        }        // Decrypt        public string Decrypt(string encryptedText)        {            byte[] encryptedBuffer = Convert.FromBase64String(encryptedText);            byte[] buffer = new byte[BufferSize];            Stream encryptedStream = null;            MemoryStream clearStream = null;            CryptoStream cryptoStream = null;            try            {                encryptedStream = new MemoryStream(encryptedBuffer);                clearStream = new MemoryStream();                cryptoStream = new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read);                int bytesRead = 0;                while ((bytesRead = cryptoStream.Read(buffer, 0, BufferSize)) > 0)                {                    clearStream.Write(buffer, 0, bytesRead);                }                buffer = clearStream.GetBuffer();                string clearText = Encoding.UTF8.GetString(buffer, 0, (int)clearStream.Length);                return clearText;            }            finally            {                if (encryptedStream != null)                {                    encryptedStream.Close();                    encryptedStream = null;                }                if (clearStream != null)                {                    clearStream.Close();                    clearStream = null;                }                if (cryptoStream != null)                {                    cryptoStream.Close();                    cryptoStream = null;                }                if (provider != null)                {                    provider.Clear();                }            }        }    }

 

 

非對稱式加密解密樣本

如果對檔案的安全性要求不是很嚴格,只是控制檔案在傳輸中的完整性,可以用散列演算法算出一個檔案的散列,然後用非對稱演算法加密並把加密後的資訊附加於檔案中,接收方使用收到的檔案中的散列驗證檔案的完整性,同時也能確認檔案的寄件者,即實現了簡單的檔案簽名的功能。

 

下面樣本示範了如何使用RSACryptoServiceProvider類加密一個字串。其中,ExpertParameter(bool)方法根據參數的真假允許獲得公開金鑰/私密金鑰對(true)或只有公開金鑰(false)。

 

 

using System;using System.Text;using System.Security.Cryptography;class Program{    static void Main()    {        string sMsg = "The message to encrypt!";        string sEnc, sDec;        Encoding utf = new UTF8Encoding();        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();        RSAParameters publicKey = rsa.ExportParameters(false);        RSAParameters publicAndPrivateKey = rsa.ExportParameters(true);        {            RSACryptoServiceProvider rsaEncryptor = new            RSACryptoServiceProvider();            rsaEncryptor.ImportParameters(publicKey);            byte[] bMsg = utf.GetBytes(sMsg);            byte[] bEnc = rsaEncryptor.Encrypt(bMsg, false);            sEnc = Convert.ToBase64String(bEnc);        }        {            RSACryptoServiceProvider rsaDecryptor = new            RSACryptoServiceProvider();            rsaDecryptor.ImportParameters(publicAndPrivateKey);            byte[] bEnc = Convert.FromBase64String(sEnc);            byte[] bDec = rsaDecryptor.Decrypt(bEnc, false);            sDec = utf.GetString(bDec);        }        Console.WriteLine("Message : " + sMsg);        Console.WriteLine("Encrypted: " + sEnc);        Console.WriteLine("Decrypted: " + sDec);    }}

 

雜湊計算樣本

以下以MD5演算法計算雜湊值為例,給出簡單樣本。

        public string MD5Crypto(string input)        {            MD5 md5Hasher = null;            try            {                // 建立? MD5CryptoServiceProvider 對象U的I執行個體a                md5Hasher = MD5.Create();                //計算Z哈u希o代a碼                byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));                StringBuilder sBuilder = new StringBuilder();                for (int i = 0; i < data.Length; i++)                {                    sBuilder.Append(data[i].ToString("X2"));                }                return sBuilder.ToString();            }            finally            {                if (md5Hasher != null)                {                    md5Hasher.Clear();                    md5Hasher.Dispose();                    md5Hasher = null;                }            }        }

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.