Может ли CryptoStream оставить базовый поток открытым?
Я создаю MemoryStream
, передаю его CryptoStream
для записи. Я хочу, чтобы CryptoStream
зашифровал и оставил MemoryStream
открытым для меня, чтобы затем прочитать что-то еще. Но как только CryptoStream
располагается, он также имеет значение MemoryStream
.
Может ли CryptoStream
оставить базу MemoryStream
как-то открыта?
using (MemoryStream scratch = new MemoryStream())
{
using (AesManaged aes = new AesManaged())
{
// <snip>
// Set some aes parameters, including Key, IV, etc.
// </snip>
ICryptoTransform encryptor = aes.CreateEncryptor();
using (CryptoStream myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write))
{
myCryptoStream.Write(someByteArray, 0, someByteArray.Length);
}
}
// Here, I'm still within the MemoryStream block, so I expect
// MemoryStream to still be usable.
scratch.Position = 0; // Throws ObjectDisposedException
byte[] scratchBytes = new byte[scratch.Length];
scratch.Read(scratchBytes,0,scratchBytes.Length);
return Convert.ToBase64String(scratchBytes);
}
Ответы
Ответ 1
Вы можете, но не сможете использовать с помощью операторов. Вам нужно будет вручную управлять удалением объекта, и вам также нужно будет вызвать FlushFinialBlock()
, чтобы убедиться, что все данные были выписаны в базовый поток перед началом работы в теме.
Как только вы закончите работу с потоком, вы можете затем распоряжаться всеми ресурсами, которые вы ожидаете в конце блока в конце.
MemoryStream scratch = null;
AesManaged aes = null;
CryptoStream myCryptoStream = null;
try
{
scratch = new MemoryStream();
aes = new AesManaged();
// <snip>
// Set some aes parameters, including Key, IV, etc.
// </snip>
ICryptoTransform encryptor = aes.CreateEncryptor();
myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write);
myCryptoStream.Write(someByteArray, 0, someByteArray.Length);
//Flush the data out so it is fully written to the underlying stream.
myCryptoStream.FlushFinalBlock();
scratch.Position = 0;
byte[] scratchBytes = new byte[scratch.Length];
scratch.Read(scratchBytes,0,scratchBytes.Length);
return Convert.ToBase64String(scratchBytes);
}
finally
{
//Dispose all of the disposeable objects we created in reverse order.
if(myCryptoStream != null)
myCryptoStream.Dispose();
if(aes != null)
aes.Dispose();
if(scratch != null)
scratch.Dispose();
}
Ответ 2
В качестве второго решения вы можете создать объект WrapperStream, который просто передает каждый вызов, за исключением Dispose/Close. Создайте обертку вокруг вашего потока памяти, передайте обертку криптовому потоку, и теперь закрытие криптопотока не касается потока памяти.
Ответ 3
Оказывается, нет необходимости разрывать использование блока {} в try {} finally {}... В конечном счете вам просто нужно использовать FlushFinalBlock() внутри оператора using и вложить что-нибудь еще внутри там по мере необходимости.
using (MemoryStream scratch = new MemoryStream())
{
using (AesManaged aes = new AesManaged())
{
// <snip>
// Set some aes parameters, including Key, IV, etc.
// </snip>
ICryptoTransform encryptor = aes.CreateEncryptor();
using (CryptoStream myCryptoStream = new CryptoStream(scratch, encryptor, CryptoStreamMode.Write))
{
myCryptoStream.Write(someByteArray, 0, someByteArray.Length);
myCryptoStream.FlushFinalBlock();
scratch.Flush(); // not sure if this is necessary
byte[] scratchBytes = scratch.ToArray();
return Convert.ToBase64String(scratchBytes);
}
}
}
Ответ 4
Начиная с .NET 4.7.2, существует второй конструктор с добавленным параметром bool, который называется leaveOpen
. Если для этого параметра установлено значение true, метод удаления CryptoStream
не будет вызывать удаление в базовом потоке.
Кроме того, другой конструктор без параметра leaveOpen
просто перенаправляет параметры в новый конструктор с leaveOpen
значением false
для leaveOpen
конструктора.
MSDN
CryptoStream.Dispose(bool disposing)
Ответ 5
Мое простое решение:
class NotClosingCryptoStream : CryptoStream
{
public NotClosingCryptoStream( Stream stream, ICryptoTransform transform, CryptoStreamMode mode )
: base( stream, transform, mode )
{
}
protected override void Dispose( bool disposing )
{
if( !HasFlushedFinalBlock )
FlushFinalBlock();
base.Dispose( false );
}
}
Ответ 6
Как ответил @CyberBasti. Я считаю, что лучшим решением является переопределить метод dispose и вызвать базу с помощью false
.
Я заглянул в справочный источник, и это показывает, что это лучшее решение, потому что вы все равно можете использовать ключевое слово using
и сделать организованный код:)
btw Я отвечаю, потому что не могу комментировать xD
Ответ 7
Используйте leaveOpen флаг CryptoStream конструктор