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#数据加密解密的key和iv

也可以使用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}");
            }
        }

 

posted @ 2020-01-09 14:30  龙骑科技  阅读(4575)  评论(0编辑  收藏  举报