Re: Deserialize, CryptoStream, and NetworkStream
From: Mike (clarksmr_at_yahoo.com)
Date: 02/27/04
- Previous message: Novice: ""Trust An Assembly" Wizard, .NET Configuartion (mscorcfg.msc) and caspol"
- In reply to: Stephen Martin: "Re: Deserialize, CryptoStream, and NetworkStream"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Date: Fri, 27 Feb 2004 16:10:31 -0500
Well, still not completely correct, but we're getting closer. Your last
message inspired me to add a loop around the serialization call in the
client, and run the test again. As long as the client serializes at least
twice, the program works as expected and the server can deserialize the
first message *without* having to close the socket. So it's not true that
the zero byte signal from the stream is essential. However, it does appear
to be the case that pumping more data through the stream is enough to cause
the Deserialize call to return. (Note also that the Deserialize call
waiting on the CryptoStream to call TranformFinalBlock is a red herring,
because this doesn't happen in the experiment I've just described.)
So, why is it the case that writing more data to the stream causes the
decrypting side to deliver the data to Deserialize, but flushing the stream
doesn't cause this?
I greatly appreciate any responses.
-- Mike
"Stephen Martin" <smartin@removethis.emsoft.andthis.ca> wrote in message
news:%23GQQb2W$DHA.2012@TK2MSFTNGP11.phx.gbl...
> You're right, my answer was a bit simplistic.
>
> When you don't use a CryptoStream the Deserialize call can read the data
> from the network stream. As you say, the serialized data includes headers
> with the data length and so it knows when the stream has finished
retrieving
> data. But when you introduce the CryptoStream it's the CryptoStream
reading
> from the network stream not the deserializer. The CryptoStream knows
nothing
> about the length expected and so cannot know that it has reached the end
of
> the data (and call TransformFinalBlock to receive the last decrypted
buffer)
> until it receives the zero byte signal from the stream.
>
> You may be able to use a stream cipher for this but I haven't looked into
> any of the stream cipher implementations.
>
> "Mike" <clarksmr@yahoo.com> wrote in message
> news:c1o3bg$q5g$1@news01.cit.cornell.edu...
> > Stephen,
> >
> > Thanks for the help, but I'm fairly certain this isn't the correct
> > explanation, for theoretical and experimental reasons.
> >
> > First, the serialization protocol ought to be able to do exactly what
you
> > say, and specify the size of the message, so that it knows when to
finish
> > deserialization.
> >
> > Second (and I should have mentioned this to begin with): if I remove
all
> > references to the CryptoStream, and simply Serialize/Deserialize from
the
> > NetworkStream, then the message is deserialized when the stream is
> > flushed -- I don't have to close it. This is the way I would expect it
to
> > work.
> >
> > So the CryptoStream is an essential part of this problem.
> >
> > Still looking for an explanation...
> >
> > -- Mike
> >
> >
> > "Stephen Martin" <smartin@removethis.emsoft.andthis.ca> wrote in message
> > news:OCzx3xV$DHA.1956@TK2MSFTNGP10.phx.gbl...
> > > This is normal for a network stream. When you flush the stream that is
> > > writing to the socket all the data is sent to the client. But as the
> > client
> > > is reading the data it has no way of knowing when the data has been
> > > completely received. It just keeps reading the stream until the stream
> > > returns zero bytes, this works fine for a file stream, memory stream,
> etc.
> > > but a network stream only returns zero bytes when the socket is
closed.
> > So,
> > > in your case the client is waiting on a Stream.Read call inside of the
> > > Deserialize method until the socket is closed.
> > >
> > > The problem is that TCP is not designed as a message oriented
protocol.
> > > Instead of Serializing/Deserializing directly to the stream
> > > Serialize/Encrypt to a buffer and then send the message with the
length
> > > prepended so that the client can know when the message is complete
> without
> > > closing the socket. Or Serialize/Encrypt to a buffer and use UDP.
> > >
> > > "Mike" <clarksmr@yahoo.com> wrote in message
> > > news:c1m205$2t0$1@news01.cit.cornell.edu...
> > > > I'm having trouble in C# getting (de)serialization to work over a
> > > > CryptoStream attached to a NetworkStream. The issue is that the
> > > > Deserialize() call blocks until the stream is closed, rather than
just
> > > > flushed.
> > > >
> > > > I'd really like to know what I'm doing wrong, so here is a short
code
> > > > listing that exhibits the problem. Any insights would be greatly
> > > > appreciated.
> > > >
> > > > -- Mike
> > > >
> > > > Files in listing: client.cs. server.cs
> > > >
> > > > //----------------------------------------------
> > > > // Begin client.cs
> > > > //----------------------------------------------
> > > > using System;
> > > > using System.Net.Sockets;
> > > > using System.Runtime.Serialization.Formatters.Binary;
> > > > using System.Collections;
> > > > using System.IO;
> > > > using System.Security.Cryptography;
> > > > using System.Threading;
> > > >
> > > > class Client
> > > > {
> > > > static void Main(string[] args)
> > > > {
> > > > // Initialize all the objects we need.
> > > > TcpClient client = new TcpClient("localhost", 8000);
> > > > NetworkStream netStream = client.GetStream();
> > > > SymmetricAlgorithm crypt = Rijndael.Create();
> > > > byte[] Key = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09,
> > > 0x10,
> > > > 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
> > > > byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09,
> > > 0x10,
> > > > 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
> > > > crypt.Key = Key;
> > > > crypt.IV = IV;
> > > > BinaryFormatter bf = new BinaryFormatter();
> > > > CryptoStream encryptedStream = new CryptoStream(netStream,
> > > > crypt.CreateEncryptor(), CryptoStreamMode.Write);
> > > > String m = "test";
> > > >
> > > > // Serialize a message to an encrypted network stream, then flush
> the
> > > > stream
> > > > Console.WriteLine("Serializing message");
> > > > Console.WriteLine("Message is: " + m);
> > > > bf.Serialize(encryptedStream, m);
> > > > Console.WriteLine("Message serialized");
> > > > encryptedStream.FlushFinalBlock();
> > > > encryptedStream.Flush();
> > > > Console.WriteLine("Stream flushed");
> > > >
> > > > // At this point, the message should already have arrived at the
> > server.
> > > > // However, you'll notice during the next 5 seconds that the
server
> > > > // will act as though it hasn't received the message.
> > > > Thread.Sleep(5000);
> > > > encryptedStream.Close();
> > > > Console.WriteLine("Stream closed");
> > > > // Now, the server will have displayed the message. So Close() is
> > doing
> > > > // something to finalize sending the message that Flush() didn't
do.
> > > >
> > > > // Finally, wait another 5 seconds to prove that Close() is what
did
> > it,
> > > > // rather than destruction of some object.
> > > > Thread.Sleep(5000);
> > > > }
> > > > }
> > > > //----------------------------------------------
> > > > // End client.cs
> > > > //----------------------------------------------
> > > >
> > > > //----------------------------------------------
> > > > // Begin server.cs
> > > > //----------------------------------------------
> > > > using System;
> > > > using System.Net;
> > > > using System.Net.Sockets;
> > > > using System.Runtime.Serialization.Formatters.Binary;
> > > > using System.Collections;
> > > > using System.IO;
> > > > using System.Security.Cryptography;
> > > > using System.Threading;
> > > >
> > > > class Server
> > > > {
> > > > static void Main(string[] args)
> > > > {
> > > > IPAddress localHost = Dns.Resolve("localhost").AddressList[0];
> > > > TcpListener server = new TcpListener(localHost, 8000);
> > > > server.Start();
> > > > TcpClient client = server.AcceptTcpClient();
> > > > NetworkStream netStream = client.GetStream();
> > > > SymmetricAlgorithm crypt = Rijndael.Create();
> > > > byte[] Key = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09,
> > > 0x10,
> > > > 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
> > > > byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09,
> > > 0x10,
> > > > 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
> > > > crypt.Key = Key;
> > > > crypt.IV = IV;
> > > > BinaryFormatter bf = new BinaryFormatter();
> > > > CryptoStream encryptedStream = new CryptoStream(netStream,
> > > > crypt.CreateDecryptor(), CryptoStreamMode.Read);
> > > >
> > > > Console.WriteLine("Deserializing message");
> > > > String m = (String) bf.Deserialize(encryptedStream);
> > > > Console.WriteLine("Message deserialized");
> > > > Console.WriteLine("Message was: " + m);
> > > > }
> > > > }
> > > > //----------------------------------------------
> > > > // End server.cs
> > > > //----------------------------------------------
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> >
> >
>
>
- Previous message: Novice: ""Trust An Assembly" Wizard, .NET Configuartion (mscorcfg.msc) and caspol"
- In reply to: Stephen Martin: "Re: Deserialize, CryptoStream, and NetworkStream"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
|