Использование класса PasswordDeriveBytes в блоке using (который удаляет его, потому что он реализует IDisposable) создает проблему, если класс используется во второй раз. Это код:
public class AES
{
protected static CryptoData localCryptoData;
static AES()
{
localCryptoData = new CryptoData();
}
public static string Encrypt(CryptoData cryptoData)
{
using (PasswordDeriveBytes pass = new PasswordDeriveBytes(cryptoData.Password, cryptoData.Salt, "SHA1", 2))
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
byte[] keyBytes = pass.GetBytes(cryptoData.KeySize / 8);
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, cryptoData.InitVector))
using (MemoryStream memoryStream = new MemoryStream())
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(cryptoData.ByteText, 0, cryptoData.ByteText.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
public static string Decrypt(CryptoData cryptoData)
{
using (PasswordDeriveBytes pass = new PasswordDeriveBytes(cryptoData.Password, cryptoData.Salt, "SHA1", 2))
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
byte[] cipherTextBytes = Convert.FromBase64String(cryptoData.Text);
byte[] keyBytes = pass.GetBytes(cryptoData.KeySize / 8);
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, cryptoData.InitVector))
using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] textBytes = new byte[cipherTextBytes.Length];
int count = cryptoStream.Read(textBytes, 0, textBytes.Length); //throws CryptographicException - Padding is invalid and cannot be removed.
return Encoding.UTF8.GetString(textBytes, 0, count);
}
}
}
Если этот класс используется таким образом:
AES.Encrypt (cryptoData);
AES.Decrypt (cryptoData);
При первом использовании вы получаете правильную зашифрованную строку AES, но в случае неудачи с исключением при попытке расшифровать ту же строку. Проблема заключается в назначении первого параметра (пароля для получения ключа) из класса PasswordDeriveBytes, когда этот пароль передается через байтовый массив. Если он задан в виде строки (из-за перегрузки), он работает нормально.
Вспомогательный класс CryptoData:
public class CryptoData
{
private string text;
public string Text
{
get { return text; }
set
{
text = value;
if (value != null)
{
ByteText = Encoding.ASCII.GetBytes(value);
}
else
{
ByteText = null;
}
}
}
public byte[] ByteText { get; private set; }
public byte[] Password { get; set; }
public int KeySize { get; set; }
public byte[] InitVector { get; set; }
public byte[] Salt { get; set; }
}
Если вы просто измените эту строку в методах:
using (PasswordDeriveBytes pass = new PasswordDeriveBytes(cryptoData.Password,
cryptoData.Salt, "SHA1", 2))
в
using (PasswordDeriveBytes pass = new PasswordDeriveBytes("somePassword",
cryptoData.Salt, "SHA1", 2))
все отлично работает. Проблема в том, что экземпляр PasswordDeriveBytes не получает байтовый массив для пароля во второй раз, из-за оператора using. Если вместо байтового массива передана строка, она работает.
Редактировать: После более подробного рассмотрения, кажется, что есть проблема в установщике свойств по умолчанию для параметра пароля. Он получает указатель массива, и поэтому он его удаляет. Он должен сделать value.clone () из массива, как в случае с массивом соли. Это определенная ошибка.
Я прав или я что-то не так делаю?
Редактировать:
* Измените первую строку в методах AES.Encrypt () и AES.Decrypt с этим, и это работает: *
using (PasswordDeriveBytes pass = new PasswordDeriveBytes(
(byte[])cryptoData.Password.Clone(),
cryptoData.Salt, "SHA1", 2))