如何从 RijndaelManaged 升级到 AES?
How to upgrade from RijndaelManaged to AES?
我的代码(如下)中有一个针对 crypt/decrypt 数据的有效解决方案,但是当我将项目升级到 DOTNET6
时,RijndaelManaged 变得过时了:
Warning SYSLIB0022 'RijndaelManaged' is obsolete: 'The Rijndael and RijndaelManaged types are obsolete. Use Aes instead.'
和
SYSLIB0023 'RNGCryptoServiceProvider' is obsolete: 'RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead.'
现在我想将其更改为 Aes/RandomNumberGenerator,但希望保持输出与原样相同。不幸的是,我不熟悉crypt/decrypt。
有人可以帮助我重写当前块以改为使用 Aes - 或者至少帮助我如何更改它并保持 public 方法以相同的方式工作?
我拥有的完整代码(按原样工作)
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);
}
}
感谢您的帮助。
据我所知,你应该可以替换
using RijndaelManaged AES = new();
和
using var AES = Aes.Create("AesManaged");
请注意,您可能希望更改变量名称以避免命名冲突或混淆。
AES 和 Rijndael 之间的唯一区别应该是 Rijndael 允许更多 blocksizes/keysizes。但是您似乎使用的是 256 位密钥和 128 位块,这应该是 AES 允许的。
我的代码(如下)中有一个针对 crypt/decrypt 数据的有效解决方案,但是当我将项目升级到 DOTNET6
时,RijndaelManaged 变得过时了:
Warning SYSLIB0022 'RijndaelManaged' is obsolete: 'The Rijndael and RijndaelManaged types are obsolete. Use Aes instead.'
和
SYSLIB0023 'RNGCryptoServiceProvider' is obsolete: 'RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead.'
现在我想将其更改为 Aes/RandomNumberGenerator,但希望保持输出与原样相同。不幸的是,我不熟悉crypt/decrypt。
有人可以帮助我重写当前块以改为使用 Aes - 或者至少帮助我如何更改它并保持 public 方法以相同的方式工作?
我拥有的完整代码(按原样工作)
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);
}
}
感谢您的帮助。
据我所知,你应该可以替换
using RijndaelManaged AES = new();
和
using var AES = Aes.Create("AesManaged");
请注意,您可能希望更改变量名称以避免命名冲突或混淆。
AES 和 Rijndael 之间的唯一区别应该是 Rijndael 允许更多 blocksizes/keysizes。但是您似乎使用的是 256 位密钥和 128 位块,这应该是 AES 允许的。