佳佳的博客
Menu
首页
《.NET Core 实战》 [No.321~325] 加密算法
Posted by
佳佳
on 2020-04-01
IT
C#
.NET Core
《.NET Core 实战》
读书笔记
<!-- # 《.NET Core 实战》 [No.221~320] Composition --> <!-- dotnet-core-encryption --> ## MD5 在哈希算法中 *MD5* 是最常见的,多用于校验密码。 一般做法是,先用密码字符串计算出 *MD5* 值,再把 *MD5* 值转换为字符串,存进数据库。 ```csharp Console.Write("请输入文本:"); string input = Console.ReadLine(); byte[] data = Encoding.UTF8.GetBytes(input); MD5 md5 = MD5.Create(); byte[] result = md5.ComputeHash(data); Console.WriteLine(BitConverter.ToString(result).Replace("-", string.Empty).ToLower()); // 请输入文本:佳佳的博客 // 0ee5d025905e0e602d8ee997dc1f128 ``` ## SHA1 对于数量不是很大的情况,例如一般文件,可以使用 *SHA1* 算法校验。 ```csharp // 随机填充文件内容 using (FileStream fsin = File.Create("ver1.smp")) { byte[] buffer = new byte[256]; Random rand = new Random(); for (int i = 0; i < 50; i++) { rand.NextBytes(buffer); fsin.Write(buffer); } } // 复制文件 File.Copy("ver1.smp", "ver2.smp", true); // 计算文件的哈希码 string curdir = Directory.GetCurrentDirectory(); string[] files = Directory.GetFiles(curdir, "*.smp"); SHA1 sha = SHA1.Create(); foreach (var f in files) { using (FileStream fs = File.OpenRead(f)) { byte[] result = sha.ComputeHash(fs); Console.WriteLine($"文件 {Path.GetFileName(f)} 的哈希码:{BitConverter.ToString(result).Replace("-", string.Empty).ToLower()}"); } } // 文件 ver1.smp 的哈希码:7a75165e69d4fafb9b9d356ae3f2c828bcb3685d // 文件 ver2.smp 的哈希码:7a75165e69d4fafb9b9d356ae3f2c828bcb3685d ``` ## AES(1) *AES* 属于*双向加密算法*(即数据被加密后可以解密),通常需要两个元素:*秘钥(Key)* 和 *初始向量(IV)*。 必须提供相同的 *Key* 和 *IV* 才可以成功解密。 双向加密需要 `CryptoStream` 类作为数据内容的读写中介。 加密/解密方法: ```csharp /// <summary> /// 加密数据 /// </summary> /// <param name="key">秘钥</param> /// <param name="iv">初始向量</param> /// <param name="content">带加密内容</param> /// <returns></returns> static byte[] EncryptData(byte[] key, byte[] iv, string content) { byte[] res = null; using (Aes aes = Aes.Create()) { using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write)) { using (StreamWriter write = new StreamWriter(cs)) { write.Write(content); } } res = ms.ToArray(); } } return res; } /// <summary> /// 解密数据 /// </summary> /// <param name="key">秘钥</param> /// <param name="iv">初始向量</param> /// <param name="dataContent">待解密数据</param> /// <returns></returns> static string DecryptData(byte[] key, byte[] iv, byte[] dataContent) { string res = null; using (Aes aes = Aes.Create()) { using (MemoryStream ms = new MemoryStream(dataContent)) { using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(key, iv), CryptoStreamMode.Read)) { using (StreamReader reader = new StreamReader(cs)) { res = reader.ReadToEnd(); } } } } return res; } ``` 测试代码: ```csharp // 待加密文本 string msgToEnc = "佳佳的博客(www.liujiajia.me)"; // 加密用的秘钥 byte[] key; // 初始向量 byte[] iv; // 使用 Aes 类的方法产生随机的秘钥和初始向量 using (Aes aes = Aes.Create()) { aes.GenerateKey(); key = aes.Key; aes.GenerateIV(); iv = aes.IV; } // 加密数据 byte[] encData = EncryptData(key, iv, msgToEnc); Console.WriteLine($"原文本:{msgToEnc}"); Console.WriteLine($"加密后:{BitConverter.ToString(encData)}"); // 解密数据 string decMsg = DecryptData(key, iv, encData); Console.WriteLine($"解密后:{decMsg}"); ``` 打印结果: ```bash 原文本:佳佳的博客(www.liujiajia.me) 加密后:96G2B+8rf7z9jk/P5OIqwQR29nY0PVbCENV43lkRlnxtT32UzUc0QVxPmX24zdfA 解密后:佳佳的博客(www.liujiajia.me) ``` ## AES(2) `Aes` 提供了一个 *Mode* 属性类型为 `CipherMode` 枚举,默认值为 *CBC* 。 若将 *Mode* 属性指定为 *CipherMode.ECB* ,在加密/解密时可以忽略初始向量(*IV*),仅使用秘钥(*Key*)即可。 但是 *ECB* 模式存在一些安全隐患,建议用于加密一些简单的、不太重要的文本信息。 加密/解密方法: ```csharp /// <summary> /// 加密数据 /// </summary> /// <param name="key">秘钥</param> /// <param name="text">待加密数据</param> /// <returns></returns> static byte[] EncryptoText(byte[] key, string text) { byte[] resData = null; using (Aes aes = Aes.Create()) { aes.Mode = CipherMode.ECB; using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(key, null), CryptoStreamMode.Write)) { using (StreamWriter writer = new StreamWriter(cs)) { writer.Write(text); } } resData = ms.ToArray(); } } return resData; } /// <summary> /// 解密数据 /// </summary> /// <param name="key">秘钥</param> /// <param name="data">带解密数据</param> /// <returns></returns> static string DecryptoText(byte[] key, byte[] data) { string text = null; using (Aes aes = Aes.Create()) { aes.Mode = CipherMode.ECB; using (MemoryStream ms = new MemoryStream(data)) { using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(key, null), CryptoStreamMode.Read)) { using (StreamReader reader = new StreamReader(cs)) { text = reader.ReadToEnd(); } } } } return text; } ``` 测试代码: ```csharp // 待加密文本 string msgToEnc = "佳佳的博客(www.liujiajia.me)"; // 加密用的秘钥 byte[] key; // 使用 Aes 类的方法产生随机的秘钥和初始向量 using (Aes aes = Aes.Create()) { aes.GenerateKey(); key = aes.Key; } // 加密数据 byte[] encData = EncryptoText(key, msgToEnc); Console.WriteLine($"原文本:{msgToEnc}"); Console.WriteLine($"加密后:{BitConverter.ToString(encData)}"); // 解密数据 string decMsg = DecryptoText(key, encData); Console.WriteLine($"解密后:{decMsg}"); ``` 打印结果: ```bash 原文本:佳佳的博客(www.liujiajia.me) 加密后:4ypzQHeNAaLSc2TPfQJlSHI8nU5QJctfBI4PClIE2i7D/QyMptshHsH6fo/fXXYk 解密后:佳佳的博客(www.liujiajia.me) ``` ## RSA *RSA* 算法使用 *公钥* 和 *私钥* 来完成加密和解密。 公钥用来加密,可以对外公开;私钥用于解密,不可以公开。 *RSA* 算法常用于对网络数据进行保护。 示例如下: ```csharp string text = "www.liujiajia.me"; Console.WriteLine($"原字符串:{text}"); byte[] key = null; byte[] encryptData = null; // 加密数据 using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { // 导出公钥和私钥 key = rsa.ExportCspBlob(true); encryptData = rsa.Encrypt(Encoding.ASCII.GetBytes(text), RSAEncryptionPadding.Pkcs1); Console.WriteLine($"加密后:{Convert.ToBase64String(encryptData)}"); } using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { // 导入公钥和私钥 rsa.ImportCspBlob(key); byte[] buffer = rsa.Decrypt(encryptData, RSAEncryptionPadding.Pkcs1); string restoreText = Encoding.ASCII.GetString(buffer); Console.WriteLine($"解密后的字符串:{restoreText}"); } ``` 运行结果: ```bash 原字符串:www.liujiajia.me 加密后:KYfaLb2SepY/zEPXZ/NkEbkCVi7oL1eBBJRgZg9L78fI5dvINDNrcg/U14kDhtuZ0Vf8sDcG OVRc4L7nFZEkh34dDDWlEoMmvsavBWQq/ZbO75PiaBcTkK/yoYb32uelquptDWYJ0jyQcsV3ijOyCQ3T 8OyGq7dMXHVrzDNE3vE= 解密后的字符串:www.liujiajia.me ``` --- > 购买本书 => [《.NET Core实战:手把手教你掌握380个精彩案例》][10] -- *周家安* 著 --- [10]:https://union-click.jd.com/jdc?e=&p=AyIGZRhaEwAQBFUZXBIyEgRSEl0QCxc3EUQDS10iXhBeGlcJDBkNXg9JHU4YDk5ER1xOGRNLGEEcVV8BXURFUFdfC0RVU1JRUy1OVxUBFQ5THlIQMm1AEkRdb11GZyNTK0BBZwYIbylWcHILWStaJQITBlYbXB0LFQJlK1sSMkBpja3tzaejG4Gx1MCKhTdUK1sRCxQBVxtTEQIQBlwrXBULIloNXwZBXUReEStrJQEiN2UbaxYyUGlUG1kUBhcGUBILQgUXDlMeUkBVRlUBS10XBkIABhkJRzIQBlQfUg%3D%3D (《.NET Core实战:手把手教你掌握380个精彩案例》)
版权声明:原创文章,未经允许不得转载。
https://www.liujiajia.me/2020/4/1/dotnet-core-encryption
“Buy me a nongfu spring”
« 《.NET Core 实战》 [No.326~329] Web 主机配置
《.NET Core 实战》 [No.306~312] 反射 »
昵称
*
电子邮箱
*
回复内容
*
(回复审核后才会显示)
提交
目录
AUTHOR
刘佳佳
江苏 - 苏州
软件工程师
梦嘉集团