.NET的加密方式有以下几种
1.Windows数据保护
特点:管理秘钥数量是0,速度快,由用户的密码决定强度,备注:使用隐式生成的密钥对字节数组进行加密和解密。
以下代码简单演示了加密和解密的过程,注意要添加引用System.Security.dll
using System.Security.Cryptography;
using System.Security;
byte[] original = { 1, 2, 3, 4, 5, 6 };
DataProtectionScope scope = DataProtectionScope.CurrentUser;
byte[] encrypted = ProtectedData.Protect(original, null, scope);//加密
Console.WriteLine("encrypted:");
foreach (byte b in encrypted)
{
Console.WriteLine(b.ToString() + " ");
}
byte[] decrypted = ProtectedData.Unprotect(encrypted, null, scope);//解密
Console.WriteLine("decrypted:" + BitConverter.ToString(decrypted));
DataProtectionScope可以选择CurrentUser或者LocalMachine。若使用CurrentUser则密钥会从当前登录用户的凭据中生成,若使用LocalMachine,则会使用一个本机范围的密钥,而该密钥对所有用户共享,所以一般使用CurrentUser。
2.散列法(Hash加密算法)
散列法提供一种单向加密的方式,也就是说无法根据密文推导出明文,非常适用于在数据库中存储密码。有MD5和SHA256的ComputeHash方法可以生成散列码。
以下代码简单演示了加密的过程:
byte[] data = System.Text.Encoding.UTF8.GetBytes("stRhon%pword");
byte[] hash = SHA256.Create().ComputeHash(data);
foreach (byte c in hash)
{
Console.WriteLine(c.ToString() + " ");
}
以下是安全等级由低到高的排序,运算速度有快到慢。
MD(16) → SHA1(20) → SHA256(32) → SHA384(48) → SHA512(64)
如果要存储密码或其他稿安全等级的敏感数据,至少使用SHA256。
注意:它们需要强制采用高密码强度的策略来防止字典攻击的威胁,例如采用Rfc2898DeriveBytes类
3.对称加密
对称加密算法在加密和解密时使用相同的密钥,Framework提供4种对称加密算法如Rijindael,Aes。
#region 对称加密/解密算法
byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };//密钥Rijndael和Aes支持16字节,24字节,和32字节的对称密钥长度
byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };//初始化向量,密码的一部分,传输加密信息是,IV以明文的方式
byte[] data = { 1, 2, 3, 4, 5, 6 };//这些是要加密的数据
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[] key2 = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };//密钥Rijndael和Aes支持16字节,24字节,和32字节的对称密钥长度
byte[] iv2 = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };//初始化向量,密码的一部分,传输加密信息是,IV以明文的方式
byte[] decrypted = new byte[6];
using (SymmetricAlgorithm algorithm2 = Aes.Create())
using (ICryptoTransform decryptor = algorithm2.CreateDecryptor(key2, iv2))
using (Stream f2 = File.OpenRead("encrypted.bin"))
using (Stream c2 = new CryptoStream(f2, decryptor, CryptoStreamMode.Read))
for (int b; (b = c2.ReadByte()) > 0; )
Console.WriteLine(b + " ");
Console.ReadLine();
#endregion
可以使用System.Cryptography命名空间下的RandomNumberGenerator来生成随机密钥或IV,具有密码学强度。
byte[] key = new byte[16];
byte[] IV = new byte[16];
RandomNumberGenerator rand= RandomNumberGenerator.Create();
rand.GetBytes(key);
rand.GetBytes(IV);
3.1 内存加密
字节数组的形式演示:
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();
}
#region 内存加密
byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 4, 5, 6, 8 };//要加密的对象
byte[] kv = new byte[16];
byte[] iv = new byte[16];
RandomNumberGenerator.Create().GetBytes(kv);
RandomNumberGenerator.Create().GetBytes(iv);//kv和iv最好不要相同
byte[] encrypted = Encrypt(data, kv, iv);
Console.WriteLine("encrpted: ");
Console.WriteLine(BitConverter.ToString(encrypted));
byte[] decrypted = Decrypt(encrypted, kv, iv);
Console.WriteLine("decrpted: ");
Console.WriteLine(BitConverter.ToString(decrypted));
Console.ReadLine();
#endregion
4.非对称加密
非对称加密需要专门制作一对密钥,这个密钥包含一个公钥和私钥,其中公钥加密信息,私钥解密信息。
注意:公钥加密算法要求加密的信息小于密钥的长度,更适合加密少量数据,如果试图加密的数据大于密钥长度的一半,则会抛出异常。
4.1 RSA类
.NET Framework 提供很多非对称加密算法,其中以RSA算法最为流行,如下所示。
#region 非对称加密
byte[] data = { 1, 2, 3, 4, 5 };
using (var ras = new RSACryptoServiceProvider())
{
/*
* 并没有指定公钥和私钥,加密程序默认使用1024位长度自动生成一个密钥对
* 当然也可以设置 var ras = new RSACryptoServiceProvider(2048)
*/
byte[] encrypted = ras.Encrypt(data, true);
byte[] decrypted = ras.Decrypt(encrypted, true);
Console.WriteLine(BitConverter.ToString(encrypted));
Console.WriteLine(BitConverter.ToString(decrypted));
}
#endregion
//创建一个密钥对,并将其存储到磁盘上
using (var rsa = new RSACryptoServiceProvider())
{
/*没有现成的密钥对,因此在调用ToXmlString会强制生成一个新的密钥对*/
File.WriteAllText("PublicKeyOnly.xml", rsa.ToXmlString(false));//仅包含公钥
File.WriteAllText("PublicPrivate.xml", rsa.ToXmlString(true));
}
//以下是加载上述代码生成的密钥对,然后对信息进行加密和解密。
byte[] data = Encoding.UTF8.GetBytes("123456789");
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);//加密
}
using (var rsaPublicPrivate = new RSACryptoServiceProvider())
{
rsaPublicPrivate.FromXmlString(publicPrivate);
decrypted = rsaPublicPrivate.Decrypt(encrypted, true);//解密
Console.WriteLine(BitConverter.ToString(decrypted));
}
4.2 数字签名
公钥算法可以对消息或文档进行数字签名。但这个散列值会用私钥进行加密从而防止伪造,而公钥用来验证这个数字签名。
byte[] data = Encoding.UTF8.GetBytes("Message to sign");
byte[] publicKey;
byte[] signnature;
object hasher = SHA1.Create();
using (var publicprivate = new RSACryptoServiceProvider())
{
signnature = publicprivate.SignData(data, hasher);
publicKey = publicprivate.ExportCspBlob(false);// public key
}
using (var publicOnly = new RSACryptoServiceProvider())
{
publicOnly.ImportCspBlob(publicKey);
Console.WriteLine(publicOnly.VerifyData(data,hasher,signnature));
data[0] = 0;
Console.WriteLine(publicOnly.VerifyData(data, hasher, signnature));
signnature = publicOnly.SignData(data, hasher);
}