问题
我想用RijndaelManaged解密加密的数据,但是结果总是空的(要么是"",要么是数据长度为零的字节数组)。
所有参数、salt和数据都是正确的,CryptoHelper.CreateRijndaelManagedAES在加密方法中得到完全相同的调用(这会产生良好的输出)。
我唯一能想到的就是我用错了溪流,但我不知道为什么.
码
public static RijndaelManaged CreateRijndaelManagedAES(byte[] passwordHash, byte[] salt)
{
RijndaelManaged aes = new RijndaelManaged
{
KeySize = 256,
BlockSize = 128,
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC
};
// Derive a key of the full Argon2 string (contains also meta data)
using Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(passwordHash, salt, 10);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
return aes;
}
public static async Task<string> EncryptDataAsync(string plainData, byte[] passwordHash, int saltSize)
{
return await Task.Run(async () =>
{
// Generate a random salt
byte[] salt = CryptoHelper.GenerateRandomSalt(saltSize);
// Write the salt unencrypted
using MemoryStream memoryStream = new MemoryStream();
await memoryStream.WriteAsync(salt);
// Encrypt the data and write the result to the stream
using RijndaelManaged aes = CryptoHelper.CreateRijndaelManagedAES(passwordHash, salt);
using CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
using StreamWriter streamWriter = new StreamWriter(cryptoStream);
await streamWriter.WriteAsync(plainData);
cryptoStream.FlushFinalBlock();
return ENCRYPTED_MAGIC + Convert.ToBase64String(memoryStream.ToArray());
});
}
public static async Task<string> DecryptDataAsync(string encryptedData, byte[] passwordHash, int saltSize)
{
if (!HasValidMagicBytes(encryptedData))
{
throw new ArgumentException("The given data isn't encrypted");
}
return await Task.Run(async () =>
{
byte[] saltAndData = Convert.FromBase64String(encryptedData.Substring(ENCRYPTED_MAGIC.Length));
byte[] salt = saltAndData.Take(saltSize).ToArray();
byte[] data = saltAndData.TakeLast(saltAndData.Length - saltSize).ToArray();
// Decrypt the data and return the result
using MemoryStream memoryStream = new MemoryStream(data);
using RijndaelManaged aes = CryptoHelper.CreateRijndaelManagedAES(passwordHash, salt);
using CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
using StreamReader streamReader = new StreamReader(cryptoStream);
return await streamReader.ReadToEndAsync();
});
}安全通知
如果您向Rfc2898DeriveBytes传递密码,请不要只使用10次迭代(如我所做的)。由于性能原因,我事先从密码中获得了一个密钥,并将结果传递给CreateRijndaelManagedAES函数。
如果您想使用带有密码的Rfc2898DeriveBytes,则至少应该使用50000次迭代(截止到2020年)。
移栽
迭代参数基本上是一个成本参数。迭代次数越多,攻击者就越难强行执行派生密码(因为他需要更多的计算能力/时间)。NIST在2017年制作了一个出版,它规定您应该尽可能多地使用环境所能处理的迭代,但至少要使用10000次。我再也找不到消息来源了,但我记得读过,你目前至少应该使用50000 (由于未来的安全)。
发布于 2020-08-13 09:26:41
问题在EncryptDataAsync方法中,即加密(在DecryptDataAsync中,即解密中,错误只会变得明显)。这是因为在调用StreamWriter之前必须先刷新memoryStream.ToArray()。此调用必须在此之前执行。
...
cryptoStream.FlushFinalBlock();
...即:
...
streamWriter.Flush();
cryptoStream.FlushFinalBlock();
...或者另一种
...
streamWriter.Close();
...这会刷新/关闭两个流,请参见StreamWriter.Flush()和StreamWriter.Close()。
https://stackoverflow.com/questions/63382645
复制相似问题