AES 加密模式演进:从 ECB、CBC 到 GCM 的 C# 深度实践
牡丹雅忻12026-08-01 16:17
System.Security.Cryptography 命名空间下的 Aes 类实现。## 二、ECB 模式:简单但危险ECB(电子密码本)模式是最基础的加密模式,每个明文分组独立加密,生成对应的密文分组。其最大缺点是同一明文块总是产生相同密文块,导致模式泄露。### 代码示例:ECB 加密与解密csharpusing System;using System.Security.Cryptography;using System.Text;public class EcbExample{ public static byte[] EncryptEcb(string plainText, byte[] key) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.Mode = CipherMode.ECB; // 设置为 ECB 模式 aes.Padding = PaddingMode.PKCS7; // 填充方式 ICryptoTransform encryptor = aes.CreateEncryptor(); byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); // 注意:ECB 不需要 IV,因此直接转换 return encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); } } public static string DecryptEcb(byte[] cipherText, byte[] key) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.PKCS7; ICryptoTransform decryptor = aes.CreateDecryptor(); byte[] decryptedBytes = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length); return Encoding.UTF8.GetString(decryptedBytes); } } public static void Main() { byte[] key = new byte[16]; // 128 位密钥 new Random().NextBytes(key); // 生产环境应使用安全随机数 string original = "Hello, AES ECB!"; byte[] encrypted = EncryptEcb(original, key); string decrypted = DecryptEcb(encrypted, key); Console.WriteLine($"原文: {original}"); Console.WriteLine($"密文 (Base64): {Convert.ToBase64String(encrypted)}"); Console.WriteLine($"解密后: {decrypted}"); }}输出示例 :原文: Hello, AES ECB!密文 (Base64): 4rV9kL2pQ8sW6xZ0...(每次运行不同)解密后: Hello, AES ECB!分析 :ECB 实现简单,但重复的明文块会导致相同密文块(如图片加密后仍可见轮廓),因此不推荐用于生产环境 。## 三、CBC 模式:引入随机性CBC(密码分组链接)模式通过将前一个密文块与当前明文块异或后再加密,解决了 ECB 的重复问题。它需要一个初始化向量(IV)来保证相同明文每次加密结果不同。### 代码示例:CBC 加密与解密csharpusing System;using System.Security.Cryptography;using System.Text;public class CbcExample{ // 加密:需要生成随机 IV public static (byte[] cipherText, byte[] iv) EncryptCbc(string plainText, byte[] key) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; // 生成随机 IV(16 字节) aes.GenerateIV(); byte[] iv = aes.IV; ICryptoTransform encryptor = aes.CreateEncryptor(); byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); byte[] cipherText = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); return (cipherText, iv); } } // 解密:需要提供 IV public static string DecryptCbc(byte[] cipherText, byte[] key, byte[] iv) { using (Aes aes = Aes.Create()) { aes.Key = key; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.IV = iv; ICryptoTransform decryptor = aes.CreateDecryptor(); byte[] decryptedBytes = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length); return Encoding.UTF8.GetString(decryptedBytes); } } public static void Main() { byte[] key = new byte[16]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(key); // 安全随机密钥 } string original = "AES CBC with random IV!"; var (encrypted, iv) = EncryptCbc(original, key); string decrypted = DecryptCbc(encrypted, key, iv); Console.WriteLine($"原文: {original}"); Console.WriteLine($"IV (Base64): {Convert.ToBase64String(iv)}"); Console.WriteLine($"密文 (Base64): {Convert.ToBase64String(encrypted)}"); Console.WriteLine($"解密后: {decrypted}"); }}输出示例 :原文: AES CBC with random IV!IV (Base64): A1b2C3d4E5f6G7h8...密文 (Base64): XyZ123AbC...(每次运行不同)解密后: AES CBC with random IV!关键点 :- IV 必须随机且每次加密不同,但无需保密- 解密时需将 IV 与密文一起传输(通常前置)- CBC 是串行加密 ,无法并行加速## 四、GCM 模式:认证加密的现代选择GCM(伽罗瓦/计数器模式)结合了计数器模式(CTR)的并行能力和GMAC认证标签,提供加密+完整性验证。它支持关联数据(AAD)的认证。### 代码示例:GCM 加密与解密(.NET 6+)csharpusing System;using System.Security.Cryptography;using System.Text;public class GcmExample{ // GCM 加密:返回密文、nonce(12字节推荐)、标签(16字节) public static (byte[] cipherText, byte[] nonce, byte[] tag) EncryptGcm( string plainText, byte[] key, byte[]? associatedData = null) { using (AesGcm aesGcm = new AesGcm(key, 16)) // 16字节标签 { // 生成 12 字节 nonce(推荐大小) byte[] nonce = new byte[12]; RandomNumberGenerator.Fill(nonce); byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); byte[] cipherText = new byte[plainBytes.Length]; byte[] tag = new byte[16]; aesGcm.Encrypt(nonce, plainBytes, cipherText, tag, associatedData); return (cipherText, nonce, tag); } } // GCM 解密:需要 nonce 和标签 public static string DecryptGcm( byte[] cipherText, byte[] key, byte[] nonce, byte[] tag, byte[]? associatedData = null) { using (AesGcm aesGcm = new AesGcm(key, 16)) { byte[] decryptedBytes = new byte[cipherText.Length]; aesGcm.Decrypt(nonce, cipherText, tag, decryptedBytes, associatedData); return Encoding.UTF8.GetString(decryptedBytes); } } public static void Main() { byte[] key = new byte[16]; RandomNumberGenerator.Fill(key); string original = "AES GCM with authentication!"; byte[] aad = Encoding.UTF8.GetBytes("关联数据(如用户ID)"); var (encrypted, nonce, tag) = EncryptGcm(original, key, aad); string decrypted = DecryptGcm(encrypted, key, nonce, tag, aad); Console.WriteLine($"原文: {original}"); Console.WriteLine($"Nonce (Base64): {Convert.ToBase64String(nonce)}"); Console.WriteLine($"标签 (Base64): {Convert.ToBase64String(tag)}"); Console.WriteLine($"密文 (Base64): {Convert.ToBase64String(encrypted)}"); Console.WriteLine($"解密后: {decrypted}"); // 演示完整性校验失败:修改一个字节 Console.WriteLine("\n--- 篡改测试 ---"); byte[] tamperedTag = (byte[])tag.Clone(); tamperedTag[0] ^= 0x01; // 翻转第一个字节 try { DecryptGcm(encrypted, key, nonce, tamperedTag, aad); } catch (CryptographicException ex) { Console.WriteLine($"解密失败(完整性校验):{ex.Message}"); } }}输出示例 :原文: AES GCM with authentication!Nonce (Base64): qR8sT2uV...标签 (Base64): W1xY3zAb...密文 (Base64): CdEfGhIj...解密后: AES GCM with authentication!--- 篡改测试 ---解密失败(完整性校验):The computed authentication tag did not match the input.优势 :- 并行加密 :CTR 模式支持多线程加速- 认证加密 :自动检测篡改或损坏- 无填充 :密文长度等于明文长度- AAD 支持 :可认证未加密的关联数据## 五、模式对比与选择建议| 特性 | ECB | CBC | GCM ||------|-----|-----|-----|| 安全性 | 低(模式泄露) | 中(需正确使用IV) | 高(认证加密) || 并行性 | 是 | 否(串行) | 是 || 完整性验证 | 否 | 否 | 是 || 密文长度 | 填充后固定 | 填充后固定 | 等于明文+标签 || 推荐场景 | 仅测试 | 传统系统 | 新项目首选 |## 六、最佳实践总结1. 永远不要在生产环境使用 ECB 模式 ,除非处理随机数据。2. CBC 模式 仍可用于遗留系统,但需注意 IV 的随机性和传输。3. GCM 是当前推荐标准 :内置认证、无填充、支持并行。适用于网络传输、文件加密等场景。4. 密钥管理 :使用 RandomNumberGenerator 生成密钥,避免硬编码。5. Nonce/IV 管理:每次加密必须使用唯一 nonce(GCM 推荐 12 字节),解密时需正确传递。通过以上 C# 代码实践,你可以根据具体需求选择最适合的 AES 模式。在构建安全应用时,优先考虑 GCM 模式,它能同时提供机密性、完整性和认证,减少开发者的安全负担。