如何将RijndaelManaged加密实现升级为.NET6兼容的AES方案
修改说明
- 所有过时API替换均完全保留原有加密参数、派生逻辑,不会改变原有输出,可无缝替换原有代码,兼容之前生成的所有密文和哈希值
- 替换
RijndaelManaged为Aes.Create(),AES是Rijndael算法的标准化实现,原有配置的256位密钥、128位块大小、CBC加密模式均完全兼容 - 替换
RNGCryptoServiceProvider为RandomNumberGenerator.GetBytes()静态方法,生成随机盐的逻辑和结果完全一致
完整修改后代码
using System.Security.Cryptography; using System.Text; namespace MyApp; internal static class AES { private static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) { byte[] encryptedBytes; byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; using (MemoryStream ms = new()) { using (Aes aes = Aes.Create()) { aes.KeySize = 256; aes.BlockSize = 128; var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); aes.Key = key.GetBytes(aes.KeySize / 8); aes.IV = key.GetBytes(aes.BlockSize / 8); aes.Mode = CipherMode.CBC; using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length); cs.Close(); } encryptedBytes = ms.ToArray(); } } return encryptedBytes; } private static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes) { byte[] decryptedBytes = null; byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; using (MemoryStream ms = new()) { using (Aes aes = Aes.Create()) { aes.KeySize = 256; aes.BlockSize = 128; var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); aes.Key = key.GetBytes(aes.KeySize / 8); aes.IV = key.GetBytes(aes.BlockSize / 8); aes.Mode = CipherMode.CBC; using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length); cs.Close(); } decryptedBytes = ms.ToArray(); } } return decryptedBytes; } public static string EncryptText(string password, string salt = "MySecretSaltWhichIWantToKeepWorking") { byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(password); byte[] passwordBytes = Encoding.UTF8.GetBytes(salt); passwordBytes = SHA256.Create().ComputeHash(passwordBytes); byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes); string result = Convert.ToBase64String(bytesEncrypted); return result; } public static string DecryptText(string hash, string salt = "MySecretSaltWhichIWantToKeepWorking") { try { byte[] bytesToBeDecrypted = Convert.FromBase64String(hash); byte[] passwordBytes = Encoding.UTF8.GetBytes(salt); passwordBytes = SHA256.Create().ComputeHash(passwordBytes); byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes); string result = Encoding.UTF8.GetString(bytesDecrypted); return result; } catch (Exception e) { return e.Message; } } private const int SALT_BYTE_SIZE = 24; private const int HASH_BYTE_SIZE = 24; private const int PBKDF2_ITERATIONS = 1000; private const int ITERATION_INDEX = 0; private const int SALT_INDEX = 1; private const int PBKDF2_INDEX = 2; public static string PBKDF2_CreateHash(string password) { byte[] salt = new byte[SALT_BYTE_SIZE]; RandomNumberGenerator.GetBytes(salt); byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE); return PBKDF2_ITERATIONS + ":" + Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash); } public static bool PBKDF2_ValidatePassword(string password, string correctHash) { char[] delimiter = { ':' }; string[] split = correctHash.Split(delimiter); int iterations = Int32.Parse(split[ITERATION_INDEX]); byte[] salt = Convert.FromBase64String(split[SALT_INDEX]); byte[] hash = Convert.FromBase64String(split[PBKDF2_INDEX]); byte[] testHash = PBKDF2(password, salt, iterations, hash.Length); return SlowEquals(hash, testHash); } private static bool SlowEquals(byte[] a, byte[] b) { uint diff = (uint)a.Length ^ (uint)b.Length; for (int i = 0; i < a.Length && i < b.Length; i++) diff |= (uint)(a[i] ^ b[i]); return diff == 0; } private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes) { Rfc2898DeriveBytes pbkdf2 = new(password, salt) { IterationCount = iterations }; return pbkdf2.GetBytes(outputBytes); } }
验证建议
可以用原有代码加密一段测试文本,再用修改后的代码解密,确认结果一致;也可以用修改后的代码加密同一段文本,对比和原有代码的加密输出完全相同,即可确认兼容性没问题。
内容的提问来源于stack exchange,提问作者Josef Širůčka
相关产品推荐
相关产品推荐

