2013-11-01 13 views
18

私はMemoryStreamを作成し、書き込みのためCryptoStreamに渡します。私はCryptoStreamを暗号化して、MemoryStreamを開いたままにして、別のものを読むようにします。しかし、すぐにCryptoStreamが処分されると、MemoryStreamも処分されます。CryptoStreamはベースストリームを開いたままにできますか?

CryptoStreamMemoryStreamはなんとか開いていますか?

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を与えた人に、私の答えはどういう意味ですか?私のポストに間違った情報がある場合、それを訂正または削除できるように私に知らせてください。私は、コードが内側の 'try-finally'に書かれている方法は不要だと思います。私はそれを削除します。私が考えることができる唯一の他のものは、 'myCryptoStream'の前に' aes'と 'scratch'が置かれているという事実です。私もそれを修正します。 –

+1

暗号化された後に基本ストリームを返すメソッドを作成し、基本ストリームを返す前にCryptoStreamを処理する場合はどうなりますか? CryptoStreamを処分するかどうかは重要ですか?またはあなたがそれを完了したときにBaseStreamを処分するだけでいいですか? –

+0

Downvoted:CryptoStreamが使用されているメソッドから基本ストリームを返す方法については説明していません。 – Hammerite

6

それは、{} {} {}最後に試しに使ってブロックばらばらにする必要がない、判明...最終的に、あなただけのusingステートメント内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()'は[msdnから] unnessasaryです(http://msdn.microsoft.com/ " –

11

2番目の解決方法として、Dispose/Closeを除くすべての呼び出しを単に渡すWrapperStreamオブジェクトを作成できます。メモリストリームの周りにラッパーを作成し、ラッパーを暗号ストリームに渡して、今度は暗号ストリームを閉じてもメモリストリームには触れません。

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の言及のように '処分 タイプ:システム。ブール値 管理リソースと非管理リソースの両方を解放する場合はtrue。管理されていないリソースのみを解放する場合はfalseです。 私が知っているように、ストリームオブジェクトは管理されていないオブジェクトなので、このソリューションはCryptoStreamが元のストリームを解放しないようにするにはどうしたらいいですか? – Gintama

0

@Cyber​​Bastiが答えたとおり。私は最高の解決策は、disposeメソッドをオーバーライドしてfalseでベースを呼び出すことだと思います。私はreference sourceに見て、あなたはまだusingキーワードを使用して、組織のコードを作ることができるので、それは、最善の解決策であることを示します:)

ところで、私は答えを作ってるんだ、私はコメントすることはできませんので

xD

関連する問題