2013-11-01 2 views
18

Я создаю MemoryStream, передаю его CryptoStream для записи. Я хочу, чтобы CryptoStream зашифровал и оставил MemoryStream открытым для меня, чтобы потом читать что-то еще. Но как только CryptoStream находится, он также располагает MemoryStream.Может ли CryptoStream оставить базовый поток открытым?

Can 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); 
} 
+0

Почему вы используете потоки в первую очередь? Просто вызовите 'encryptor.TransformFinalBlock' на входные байты. Потоки в основном полезны для инкрементного шифрования/дешифрования, но не тогда, когда у вас есть все доступные данные одновременно. – CodesInChaos

ответ

9

Вы можете, но не можете использовать с помощью утверждений. Вам нужно будет вручную управлять удалением объекта, и вам также нужно будет позвонить 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(); 
} 
+1

Тому, кто дал мне -1, как насчет моего ответа, вы считали «не полезным», чтобы оправдать -1? Если в моем сообщении есть некорректная информация, сообщите мне, чтобы я мог ее исправить или удалить. Я предполагаю, что то, как написан код, внутренняя 'try-finally' не нужна. Я удалю его. Единственное, что я могу придумать, это тот факт, что 'aes' и' scratch' удаляются до 'myCryptoStream'. Я тоже исправлю это. –

+1

Что делать, если вы хотите написать метод, возвращающий базовый поток после его зашифрования и уничтожить CryptoStream, прежде чем возвращать базовый поток? Имеет ли значение, если вы выбрали CryptoStream? или это прекрасно, чтобы просто избавиться от BaseStream, когда вы сделали с ним? –

+0

Downvoted: не обращается к тому, как вернуть базовый поток из метода, в котором используется CryptoStream. – Hammerite

6

Оказывается, нет никакой необходимости ломать врозь с помощью {} блока в попытке {} {}, наконец ... В конце концов, вы просто должны использовать FlushFinalBlock() внутри с помощью заявления, и гнездо что-нибудь еще там, где необходимо.

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); 
     } 
    } 
} 
+2

'scrach.Flush()' действительно unnessasary, [из msdn] (http://msdn.microsoft.com/ en-us/library/system.io.memorystream.flush.aspx) "* Переопределяет метод Stream.Flush, так что никаких действий не выполняется. *" –

11

В качестве второго решения, вы можете сделать объект WrapperStream, который просто проходит каждый вызов вместе для Dispose/Закрыть исключением. Сделайте обертку вокруг вашего потока памяти, передайте обертку криптовому потоку, и теперь закрытие криптопотока не касается потока памяти.

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); 
    } 
}
+0

это работает, но у меня есть вопрос: как упоминается MSDN 'распоряжение Тип: Система.Boolean true, чтобы освободить как управляемые, так и неуправляемые ресурсы; false, чтобы освободить только неуправляемые ресурсы'. Но, как я знаю, объекты Stream являются неуправляемыми объектами, поэтому как это решение предотвратит CryptoStream не освободить базовый поток? – Gintama

0

Как ответил @CyberBasti. Я считаю, что лучшим решением является переопределить метод dispose и вызвать базу с false.

Я посмотрел в reference source, и это показывает, что лучшее решение, потому что вы все еще можете использовать ключевое слово using и сделать организованный код :)

кстати я делаю ответ, потому что я не могу комментировать xD

Смежные вопросы