Использование класса PasswordDeriveBytes в используемом блоке (который его использует, поскольку оно реализует IDisposable) создает проблему, если класс используется во второй раз. Это код:PasswordDeriveBytes (System.Security.Cryptography) терпит неудачу, если установлено
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() массива, как в случае с массивом солей. Это определенная ошибка.
Я прав, или я делаю что-то неправильно?
Edit:
* Изменение первая строка в AES.Encrypt() и AES.Decrypt методы с этим и работает: *
using (PasswordDeriveBytes pass = new PasswordDeriveBytes(
(byte[])cryptoData.Password.Clone(),
cryptoData.Salt, "SHA1", 2))
Вы не можете использовать объект после его удаления. –
Пожалуйста, прочитайте и поймите код. Никто не использует один и тот же объект дважды. Существуют разные методы. – mileski
Можете ли вы опубликовать данные об исключениях, включая трассировку стека? –