C#數據Encrypt加密Encrypt解密的算法使用

C#數據Encrypt加密Encrypt解密的算法使用,如下圖所示的加密和解密的方式

 

該框架還爲在System.Security.Cryptography.Xml中創建和驗證基於xml的簽名以及在System.Security.Cryptography.X509Certificates中使用數字證書的類型提供了更專門的支持

 

 1、Windows Data Protection 數據保護

File.WriteAllText ("myfile.txt", "");
File.Encrypt ("myfile.txt");
File.AppendAllText ("myfile.txt", "sensitive data");


ProtectedData API通過ProtectedData 類-提供了兩個靜態方法:

public static byte[] Protect (byte[] userData, byte[] optionalEntropy,DataProtectionScope scope);

public static byte[] Unprotect (byte[] encryptedData, byte[] optionalEntropy,DataProtectionScope scope);

很多在的System.Security.Cryptography類都存在mscorlib.dll and System.dll之中,但是ProtectedData 是一個例外,它存在System.Security.dll.

下面是一個加密和解密:

byte[] original = {1, 2, 3, 4, 5};
DataProtectionScope scope = DataProtectionScope.CurrentUser;
byte[] encrypted = ProtectedData.Protect (original, null, scope);
byte[] decrypted = ProtectedData.Unprotect (encrypted, null, scope);
// decrypted is now {1, 2, 3, 4, 5}

2、Hashing 哈希算法

哈希算法主要是使用HashAlgorithm 哈希算法中的ComputeHash 例如 :SHA256 和 MD5 :

哈希可以對數據流stream加密(嚴格意義上來說,其實md5應用更多的是對文件的完整性的校驗,主要是判斷文件是都被修改或者損壞等)

byte[] hash;
using (Stream fs = File.OpenRead ("checkme.doc"))
hash = MD5.Create().ComputeHash (fs); // hash is 16 bytes long

或者字節數組

byte[] data = System.Text.Encoding.UTF8.GetBytes ("stRhong%pword");
byte[] hash = SHA256.Create().ComputeHash (data);

 

3、Symmetric Encryption 對稱加密解密

對稱加密使用與解密相同的密鑰,.NET Framework框架提供了四種對稱算法,Rijndael是其中的佼佼者(發音爲“Rhine Dahl”或“Rain Doll”)。Rijndael既快速又安全,

•從.NET Framework框架1.0開始就可用Rijndael類

•在框架3.5中引入Aes類

除了Aes不允許您通過更改塊大小來削弱密碼之外,這兩者幾乎是相同的。Aes是由CLR的安全團隊推薦的。Rijndael和Aes允許長度爲16、24或32字節的對稱密鑰:目前都認爲是安全的。

下面是如何使用一個16字節的的密鑰加密的一系列字節,並把他們寫入文件:

加密

byte[] key = {145,12,32,245,98,132,98,214,6,77,131,44,221,3,9,50};
byte[] iv = {15,122,132,5,93,198,44,31,9,39,241,49,250,188,80,7};
byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting.
using (SymmetricAlgorithm algorithm = Aes.Create())
using (ICryptoTransform encryptor = algorithm.CreateEncryptor (key, iv))
using (Stream f = File.Create ("encrypted.bin"))
using (Stream c = new CryptoStream (f, encryptor, CryptoStreamMode.Write))
c.Write (data, 0, data.Length);

解密

byte[] key = {145,12,32,245,98,132,98,214,6,77,131,44,221,3,9,50};
byte[] iv = {15,122,132,5,93,198,44,31,9,39,241,49,250,188,80,7};
byte[] decrypted = new byte[5];
using (SymmetricAlgorithm algorithm = Aes.Create())
using (ICryptoTransform decryptor = algorithm.CreateDecryptor (key, iv))
using (Stream f = File.OpenRead ("encrypted.bin"))
using (Stream c = new CryptoStream (f, decryptor, CryptoStreamMode.Read))
for (int b; (b = c.ReadByte()) > −1;)
Console.Write (b + " "); // 1 2 3 4 5

 

 

C#數據加密解密的非

也可以使用System.Cryptography的RandomNumberGenerator 來產生上面的 key 和 iv,

byte[] key = new byte [16];
byte[] iv = new byte [16];
RandomNumberGenerator rand = RandomNumberGenerator.Create();
rand.GetBytes (key);
rand.GetBytes (iv);

System.Cryptography的RandomNumberGenerator 它產生的數字確實是不可預測的,或者是複雜加密的( 而 System.Random隨機類無法保證提供相同的功能)。

 

4、Encrypting in Memory 在內存中的加密解密

加密和解密

public static byte[] Encrypt (byte[] data, byte[] key, byte[] iv)
{
using (Aes algorithm = Aes.Create())
using (ICryptoTransform encryptor = algorithm.CreateEncryptor (key, iv))
return Crypt (data, encryptor);
}
public static byte[] Decrypt (byte[] data, byte[] key, byte[] iv)
{
using (Aes algorithm = Aes.Create())
using (ICryptoTransform decryptor = algorithm.CreateDecryptor (key, iv))
return Crypt (data, decryptor);
}
static byte[] Crypt (byte[] data, ICryptoTransform cryptor)
{
MemoryStream m = new MemoryStream();
using (Stream c = new CryptoStream (m, cryptor, CryptoStreamMode.Write))
c.Write (data, 0, data.Length);
return m.ToArray();
}

下面時調用上面的加密和解密

public static string Encrypt (string data, byte[] key, byte[] iv)
{
return Convert.ToBase64String (Encrypt (Encoding.UTF8.GetBytes (data), key, iv));
}
public static string Decrypt (string data, byte[] key, byte[] iv)
{
return Encoding.UTF8.GetString (Decrypt (Convert.FromBase64String (data), key, iv));
}
byte[] kiv = new byte[16];
RandomNumberGenerator.Create().GetBytes (kiv);
string encrypted = Encrypt ("Yeah!", kiv, kiv);
Console.WriteLine (encrypted); // R1/5gYvcxyR2vzPjnT7yaQ==
string decrypted = Decrypt (encrypted, kiv, kiv);
Console.WriteLine (decrypted); // Yeah!

 

5、Chaining Encryption Streams 鏈式加密流

key和iv可以使用上述的RandomNumberGenerator來產生,也可以使用默認的

// Use default key/iv for demo.
using (Aes algorithm = Aes.Create())
{
using (ICryptoTransform encryptor = algorithm.CreateEncryptor())
using (Stream f = File.Create ("serious.bin"))
using (Stream c = new CryptoStream (f,encryptor,CryptoStreamMode.Write))
using (Stream d = new DeflateStream (c, CompressionMode.Compress))
using (StreamWriter w = new StreamWriter (d))
await w.WriteLineAsync ("Small and secure!");
using (ICryptoTransform decryptor = algorithm.CreateDecryptor())
using (Stream f = File.OpenRead ("serious.bin"))
using (Stream c = new CryptoStream (f, decryptor, CryptoStreamMode.Read))
using (Stream d = new DeflateStream (c, CompressionMode.Decompress))
using (StreamReader r = new StreamReader (d))
Console.WriteLine (await r.ReadLineAsync()); // Small and secure!
}

鏈式流加密和壓縮的過程如下圖所示:

 

 

上面的方法可以收用一句嵌套的語法來寫

using (ICryptoTransform encryptor = algorithm.CreateEncryptor())
using(StreamWriter w = new StreamWriter (new DeflateStream (new CryptoStream (File.Create ("serious.bin"),encryptor,CryptoStreamMode.Write),CompressionMode.Compress)))

6、Public Key Encryption and Signing  非對稱加密解密

6.1 RSA Class

使用默認的公鑰和私鑰

byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting.
using (var rsa = new RSACryptoServiceProvider())
{
byte[] encrypted = rsa.Encrypt (data, true);
byte[] decrypted = rsa.Decrypt (encrypted, true);
}

使用自動產生的公鑰和私鑰,方法ImportCspBlob和ExportCspBlob以字節數組格式加載和保存公鑰和私鑰。FromXmlString和ToXmlString以字符串格式(包含XML片段的字符串)加載和保存公鑰和私鑰。方法中的bool標誌允許您在保存時指示是否包含私鑰。

下面是如何製造一個密鑰對,並將其保存到磁盤指定文件:

 public static void TestEncryptgrapg()
        {

            //byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting.
            //using (var rsa = new RSACryptoServiceProvider())
            //{
            //    byte[] encrypted = rsa.Encrypt(data, true);
            //    byte[] decrypted = rsa.Decrypt(encrypted, true);
            //}

            using var rsa = new RSACryptoServiceProvider();
            File.WriteAllText("PublicKeyOnly.xml", rsa.ToXmlString(false));
            File.WriteAllText("PublicPrivate.xml", rsa.ToXmlString(true));

            byte[] data = Encoding.UTF8.GetBytes("Message to encrypt");
            string publicKeyOnly = File.ReadAllText("PublicKeyOnly.xml");
            string publicPrivate = File.ReadAllText("PublicPrivate.xml");
            byte[] encrypted, decrypted;
            using (var rsaPublicOnly = new RSACryptoServiceProvider())
            {
                rsaPublicOnly.FromXmlString(publicKeyOnly);
                encrypted = rsaPublicOnly.Encrypt(data, true);
                // 下面的這解密就會報錯,因爲需要私鑰解密
                // decrypted = rsaPublicOnly.Decrypt (encrypted, true);
            }
            using (var rsaPublicPrivate = new RSACryptoServiceProvider())
            {
                // With the private key we can successfully decrypt:
                rsaPublicPrivate.FromXmlString(publicPrivate);
                decrypted = rsaPublicPrivate.Encrypt(encrypted, true);
                string ss = Encoding.UTF8.GetString(decrypted);
            }
        }

 

6.2 Digital Signing數字簽名

公鑰算法也可用於對消息或文檔進行數字簽名。簽名類似於散列,只是它的產生需要私鑰,因此不能僞造。公鑰用於驗證簽名。這裏有一個例子:

byte[] data = Encoding.UTF8.GetBytes ("Message to sign");
byte[] publicKey;
byte[] signature;
object hasher = SHA1.Create(); // Our chosen hashing algorithm.
// Generate a new key pair, then sign the data with it:
using (var publicPrivate = new RSACryptoServiceProvider())
{
signature = publicPrivate.SignData (data, hasher);
publicKey = publicPrivate.ExportCspBlob (false); // get public key
}
// Create a fresh RSA using just the public key, then test the signature.
using (var publicOnly = new RSACryptoServiceProvider())
{
publicOnly.ImportCspBlob (publicKey);
Console.Write (publicOnly.VerifyData (data, hasher, signature)); // True
// Let's now tamper with the data, and recheck the signature:
data[0] = 0;
Console.Write (publicOnly.VerifyData (data, hasher, signature)); // False
// The following throws an exception as we're lacking a private key:
signature = publicOnly.SignData (data, hasher);
}

簽名首先對數據進行散列,然後將非對稱算法應用於結果散列。由於散列具有較小的固定大小,因此可以相對快速地對大型文檔進行簽名(公鑰加密比散列更加cpu密集型)。如果需要,可以自己進行哈希,然後調用SignHash而不是SignData

using (var rsa = new RSACryptoServiceProvider())
{
byte[] hash = SHA1.Create().ComputeHash (data);
signature = rsa.SignHash (hash, CryptoConfig.MapNameToOID ("SHA1"));
...
}

簡單的說就是 signature = publicPrivate.SignData(data, hasher);這一句換成下面兩句

byte[] hash = SHA1.Create().ComputeHash(data);

signature = publicPrivate.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));

與SignData不同的是SignHash仍然需要知道您使用的散列算法;CryptoConfig.MapNameToOID通過友好的名稱(如“SHA1”)以正確的格式提供此信息。

RSACryptoServiceProvider生成與密鑰大小匹配的簽名。目前,主流算法生成的安全簽名明顯小於128字節(例如,適合產品激活碼)。

要使簽名有效,接收方必須知道並信任發送方的公鑰。這可以通過預先通信、預配置或站點證書實現。站點證書是由獨立的可信權威機構簽署的發起者的公鑰和名稱本身的電子記錄。名稱空間System.Security.Cryptography.X509Certificates定義了使用證書的類型。

 

對稱算法使用---RSACryptoServiceProvider   Asymmetric algorithms--Encrypt Encrypt

C#數據Encrypt加密Encrypt解密的相關算法可以參考System.Security.Cryptography,這個類庫中包含MD5,SHA1,SHA256,SHA384,SHA512

MD5 and SHA256 are two of the HashAlgorithm subtypes provided by the .NET Framework. Here are all the major algorithms, in ascending order of security (and hash
length, in bytes):
MD5(16) → SHA1(20) → SHA256(32) → SHA384(48) → SHA512(64)
The shorter the algorithm, the faster it executes. MD5 is more than 20 times faster than SHA512 and is well suited to calculating file checksums. You can hash hundreds
of megabytes per second with MD5 , and then store its result in a Guid . (A Guid happens to be exactly 16 bytes long, and as a value type it is more tractable than a byte array;
you can meaningfully compare Guid s with the simple equality operator, for instance.)
However, shorter hashes increase the possibility of collision (two distinct files yielding the same hash).
Use at least SHA256 when hashing passwords or other securitysensitive data. MD5 and SHA1 are considered insecure for this
purpose, and are suitable to protect only against accidental corruption, not deliberate tampering.
SHA384 is no faster than SHA512 , so if you want more security than SHA256 , you may as well use SHA512

 

引用using System.Security.Cryptography;

代碼如下:

static void Main(string[] args)
        {
            log4net.Config.XmlConfigurator.Configure();
            Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
            TestDigitalSigning();

            //TestEncryptgraph();
            TestDigitalSigning();
            Console.ReadLine();
        }

        public static void TestDigitalSigning()
        {

            //byte[] data = Encoding.UTF8.GetBytes("Message to sign");
            //byte[] publicKey;
            //byte[] signature;
            //object hasher = SHA1.Create(); // Our chosen hashing algorithm.
            //// Generate a new key pair, then sign the data with it:
            //using (var publicPrivate = new RSACryptoServiceProvider())
            //{
            //    signature = publicPrivate.SignData(data, hasher);
            //    publicKey = publicPrivate.ExportCspBlob(false); // get public key
            //}
            //// Create a fresh RSA using just the public key, then test the signature.
            //using (var publicOnly = new RSACryptoServiceProvider())
            //{
            //    publicOnly.ImportCspBlob(publicKey);
            //    Console.Write(publicOnly.VerifyData(data, hasher, signature)); // True
            //    string ss = Encoding.UTF8.GetString(data);
            //    WriteLog(ss);

            //    // Let's now tamper with the data, and recheck the signature:
            //    data[0] = 0;
            //    Console.Write(publicOnly.VerifyData(data, hasher, signature)); // False
            //    // The following throws an exception as we're lacking a private key:
            //    signature = publicOnly.SignData(data, hasher);
            //}

            byte[] data = Encoding.UTF8.GetBytes("Message to sign");
            byte[] publicKey;
            byte[] signature;
            object hasher = SHA1.Create(); // Our chosen hashing algorithm.
            // Generate a new key pair, then sign the data with it:
            using (var publicPrivate = new RSACryptoServiceProvider())
            {
                //signature = publicPrivate.SignData(data, hasher);
                byte[] hash = SHA1.Create().ComputeHash(data);
                signature = publicPrivate.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
                publicKey = publicPrivate.ExportCspBlob(false); // get public key
            }
           
            // Create a fresh RSA using just the public key, then test the signature.
            using (var publicOnly = new RSACryptoServiceProvider())
            {
                publicOnly.ImportCspBlob(publicKey);
                Console.Write(publicOnly.VerifyData(data, hasher, signature)); // True
                string ss = Encoding.UTF8.GetString(data);
                WriteLog(ss);

                // Let's now tamper with the data, and recheck the signature:
                data[0] = 0;
                Console.Write(publicOnly.VerifyData(data, hasher, signature)); // False
                // The following throws an exception as we're lacking a private key:
                signature = publicOnly.SignData(data, hasher);
            }

        }

        public static void TestEncryptgraph()
        {

            //byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting.
            //using (var rsa = new RSACryptoServiceProvider())
            //{
            //    byte[] encrypted = rsa.Encrypt(data, true);
            //    byte[] decrypted = rsa.Decrypt(encrypted, true);
            //}

            using var rsa = new RSACryptoServiceProvider();
            File.WriteAllText("PublicKeyOnly.xml", rsa.ToXmlString(false));
            File.WriteAllText("PublicPrivate.xml", rsa.ToXmlString(true));

            byte[] data = Encoding.UTF8.GetBytes("Message to encrypt");
            string publicKeyOnly = File.ReadAllText("PublicKeyOnly.xml");
            string publicPrivate = File.ReadAllText("PublicPrivate.xml");
            byte[] encrypted, decrypted;
            using (var rsaPublicOnly = new RSACryptoServiceProvider())
            {
                rsaPublicOnly.FromXmlString(publicKeyOnly);
                encrypted = rsaPublicOnly.Encrypt(data, true);
                // 下面的這解密就會報錯,因爲需要私鑰解密
                // decrypted = rsaPublicOnly.Decrypt (encrypted, true);
            }
            using (var rsaPublicPrivate = new RSACryptoServiceProvider())
            {
                // With the private key we can successfully decrypt:
                rsaPublicPrivate.FromXmlString(publicPrivate);
                decrypted = rsaPublicPrivate.Encrypt(encrypted, true);
                string ss = Encoding.UTF8.GetString(decrypted);
                Console.ForegroundColor = color;
                Console.WriteLine($"輸出信息:回的數據是:{ss}");
            }
        }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章