如何从 RijndaelManaged 升级到 AES?

Jos*_*čka 19 c# cryptography aes rijndaelmanaged

我有一个用于在代码中加密/解密数据的工作解决方案(如下),但是当我将项目升级到 时DOTNET6,RijndaelManaged 就变得过时了:

警告 SYSLIB0022“RijndaelManaged”已过时:“Rijndael 和 RijndaelManaged 类型已过时。使用 Aes 代替。

SYSLIB0023“RNGCryptoServiceProvider”已过时:“RNGCryptoServiceProvider 已过时”。要生成随机数,请使用 RandomNumberGenerator 静态方法之一。

现在我想将其更改为 Aes/RandomNumberGenerator,但希望保持输出的方式与原样相同。不幸的是,我不熟悉加密/解密。

有人可以帮助我重写当前的块以使用 Aes 来代替 - 或者至少帮助我如何改变它并保持公共方法以相同的方式工作?

我有完整的代码(它按原样工作)

using System.Security.Cryptography;

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 RijndaelManaged AES = new(); // This reports Warning  SYSLIB0022  'RijndaelManaged' is obsolete: 'The Rijndael and RijndaelManaged types are obsolete. Use Aes instead.
            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 RijndaelManaged AES = new(); // This reports Warning  SYSLIB0022  'RijndaelManaged' is obsolete: 'The Rijndael and RijndaelManaged types are obsolete. Use Aes instead.
            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)
    {
        RNGCryptoServiceProvider csprng = new(); // This reports SYSLIB0023 'RNGCryptoServiceProvider' is obsolete: 'RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead.'
        byte[] salt = new byte[SALT_BYTE_SIZE];
        csprng.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*asH 27

据我所知,你应该能够替换

using RijndaelManaged AES = new();
Run Code Online (Sandbox Code Playgroud)

using var AES = Aes.Create("AesManaged");
Run Code Online (Sandbox Code Playgroud)

请注意,您可能需要更改变量名称以避免命名冲突或混淆。

AES 和 Rijndael 之间的唯一区别应该是 Rijndael 允许更多的块大小/密钥大小。但您似乎使用 256 位密钥和 128 位块,这应该是 AES 允许的。

  • 您可以执行 `var AES = Aes.Create("AesManaged")!;` 来停止空警告 (3认同)
  • 看起来需要使用:Aes.Create(); (3认同)
  • @matronator我会参考[文档](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes.create?view=net-6.0)。不幸的是,尚不清楚何时返回 null。我的猜测是当论证无效时。 (2认同)