Я реализую методы шифрования/дешифрования, как в этом примере. Проблема в том, что массив байтов в методе EncryptString пуст; таким образом, результирующая строка тоже пуста. Как решить проблему?
using System.Security.Cryptography;
using System.Text;
Crypto crypto = new();
string test = "test";
string encrypted = crypto.EncryptString(test);
string decrypted = crypto.DecryptString(encrypted);
Console.WriteLine($"{test}\n{encrypted}\n{decrypted}");
Console.ReadKey();
class Crypto
{
byte[] key = Encoding.UTF8.GetBytes("01234567890123456789012345678901");
byte[] iv = new byte[16];
public string EncryptString(string plainText)
{
using Aes aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using MemoryStream memoryStream = new();
using CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write);
using StreamWriter streamWriter = new(cryptoStream);
streamWriter.Write(plainText);
// Array is empty here
byte[] array = memoryStream.ToArray();
return Encoding.UTF8.GetString(array);
}
public string DecryptString(string cipherText)
{
using Aes aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using MemoryStream memoryStream = new(Encoding.UTF8.GetBytes(cipherText));
using CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read);
using StreamReader streamReader = new(cryptoStream);
string decrypted = streamReader.ReadToEnd();
return decrypted;
}
}
Да, похоже, что StreamWriter нужно удалить перед вызовом MemoryStream.
Вместо этого вы можете Flush()
@JoelCoehoorn просто Flush() на StreamWriter в данном случае недостаточно. Да, он запишет данные в базовый CryptoStream и даже вызовет Flush по этому поводу CryptoStream, но вам нужно вызвать FlushFinalBlock, а этого не будет сделано. Однако закрытие StreamWriter в этом случае закроет базовый CryptoStream и очистит последний блок.





Обратите внимание, что в коде, который вы пытаетесь скопировать, есть:
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
StreamWriter закрывается (удаляется) перед вызовом msEncrypt.ToArray(). В вашем коде все по-другому - StreamWriter не закрывается до конца области видимости (из-за использования операторов), поэтому при использовании memoryStream.ToArray() в этот поток еще ничего не записывается. Простое исправление:
using MemoryStream memoryStream = new();
using CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write);
using StreamWriter streamWriter = new(cryptoStream);
streamWriter.Write(plainText);
streamWriter.Close();
byte[] array = memoryStream.ToArray();
Или лучше — просто не используйте операторы using размером с областью действия там, где в этом нет необходимости.
Кроме того, НЕ используйте кодировку UTF8 для результата шифрования. Результатом шифрования являются двоичные данные, а не текст. Если вам необходимо сохранить его как строку, используйте что-то вроде кодировки base64, а не кодировку текста, например UTF8.
Хороший улов по части UTF8. Если вы не заметили, мне пришлось бы дать ответ (вики-сообщество, поскольку на самом деле это не касается вопроса), чтобы указать на это. Возможно, он также захочет пересмотреть кодировку раньше, поскольку строки .Net по умолчанию не имеют формата UTF8. Кроме того, я бы сделал так, чтобы тип Crypto требовал Key как часть конструктора, а не жестко его кодировал.
@JoelCoehoorn iv в этом случае также жестко запрограммирован (все нули), что как бы противоречит его цели.
Есть причина, по которой образец на странице, с которой вы работаете, использует операторы
using, а не объявленияusing. Возможно, начните именно с кода в образце, а затем изменяйте его более медленно/осторожно.