Reputation: 426
I have a little problem with an XML file and a Stream
. I create and save an XML file in a Stream
, encrypt the Stream
and then save it to a normal file.
I want to read this XML, however I can only do this if I use a FileStream
and write a decrypted file to disk.
Is there a way to decrypt and keep this file in memory?
This is my code:
XMLDecriptato = New MemoryStream()
Using stream_readerX As New StreamReader(XMLDecriptato, Text.Encoding.UTF8)
XMLDecriptato.SetLength(0)
Dim FStreamCrypted As FileStream = File.Open(varTitolo, FileMode.Open, FileAccess.Read)
FStreamCrypted.Seek(0, SeekOrigin.Begin)
CryptStream(Pass, FStreamCrypted, XMLDecriptato, Type.Decrypt)
'try to read the stream
Dim xDocumentX As New XmlDocument()
xDocumentX.Load(stream_readerX) 'here is the error
End Using
It keeps saying that the Stream
is closed. I have tried also another way. The only one that works is to write the stream to the hard disk with a FileStream
.
And that is the Encrypt/Decrypt Sub:
Public Sub CryptStream(ByVal Psw As String, ByVal IN_Stream As Stream, ByVal OUT_Stream As Stream, ByVal CrtType As CryptType)
Dim AES_Provider As New AesCryptoServiceProvider()
Dim Key_Size_Bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
Key_Size_Bits = i
Exit For
End If
Next i
Dim Block_Size_Bits As Integer = AES_Provider.BlockSize
Dim Key() As Byte = Nothing
Dim IV() As Byte = Nothing
Dim Salt() As Byte = "//my salt//"
MakeKeyAndIV(Psw, Salt, Key_Size_Bits, Block_Size_Bits, Key, IV)
Dim Crypto_Transform As ICryptoTransform = Nothing
Select Case CrtType
Case CryptType.Encrypt
Crypto_Transform = AES_Provider.CreateEncryptor(key, iv)
Case CryptType.Decrypt
Crypto_Transform = AES_Provider.CreateDecryptor(key, iv)
End Select
If Crypto_Transform Is Nothing Then Exit Sub
Try
Using Crypto_Stream As New CryptoStream(OUT_Stream, Crypto_Transform, CryptoStreamMode.Write)
Const Block_Size As Integer = 1024
Dim Buffer(Block_Size) As Byte
Dim Bytes_Read As Integer
Do
Bytes_Read = IN_Stream.Read(Buffer, 0, Block_Size)
If (Bytes_Read = 0) Then Exit Do
Crypto_Stream.Write(Buffer, 0, Bytes_Read)
Loop
End Using
Catch ex As Exception
End Try
Crypto_Transform.Dispose()
End Sub
Upvotes: 0
Views: 297
Reputation: 18310
It turns out that when CryptoStream.Dispose()
is called by the Using/End Using
block, the CryptoStream
also disposes the underlying stream (in this case your MemoryStream
).
This behaviour can be confirmed by checking Microsoft's Reference Source.
Since the CryptoStream
doesn't have a LeaveOpen
flag like the StreamReader
does since .NET 4.5 and up, I removed the Using
block and wrote the necessary calls on my own for your method.
The changes:
Public Sub CryptStream(ByVal Psw As String, ByVal IN_Stream As Stream, ByVal OUT_Stream As Stream, ByVal CrtType As CryptType, Optional ByVal LeaveOpen As Boolean = False)
...code...
Try
Dim Crypto_Stream As New CryptoStream(OUT_Stream, Crypto_Transform, CryptoStreamMode.Write)
Const Block_Size As Integer = 1024
Dim Buffer(Block_Size) As Byte
Dim Bytes_Read As Integer
Do
Bytes_Read = IN_Stream.Read(Buffer, 0, Block_Size)
If (Bytes_Read = 0) Then Exit Do
Crypto_Stream.Write(Buffer, 0, Bytes_Read)
Loop
If Crypto_Stream.HasFlushedFinalBlock = False Then Crypto_Stream.FlushFinalBlock()
If LeaveOpen = False Then
Crypto_Stream.Dispose()
End If
Catch ex As Exception
End Try
...code...
End Sub
And since data will be fed into the MemoryStream
its position will have changed, so you have to reset that too before loading the XML document:
XMLDecriptato = New MemoryStream()
Using stream_readerX As New StreamReader(XMLDecriptato, System.Text.Encoding.UTF8)
Dim FStreamCrypted As FileStream = File.Open(OpenFileDialog1.FileName, FileMode.Open, FileAccess.Read)
CryptStream(Pass, FStreamCrypted, XMLDecriptato, CryptType.Decrypt, True) 'True = Leave the underlying stream open.
XMLDecriptato.Seek(0, SeekOrigin.Begin) 'Reset the MemoryStream's position.
Dim xDocumentX As New XmlDocument()
xDocumentX.Load(stream_readerX)
End Using
As you might have noticed I removed the FStreamCrypted.Seek(0, SeekOrigin.Begin)
line. This was because you've just opened the stream and done nothing with it, so the position will already be at 0.
Hope this helps!
Upvotes: 1