CryptoStream problem

  • Thread starter Thread starter Ayende Rahien
  • Start date Start date
A

Ayende Rahien

I've a problem in my code using NetworkStream.
I've a server which listen to a port, and then Read() from it, and a
client that send data.
My NetworkStream is wrapped in a CryptoStream, and my problem is that I
don't get all the data that I send.
When I use NetworkStream, all is working properly, but when I use
CryptoStream (initialize to use the NetworkStream), I only get partial data.

Anyone knows why this is happenning?
I would rather avoid using the CryptoStream all-together, but I can't
find any documentation on using TransformBlock & TransformFinalBlock.

Thanks in advance,
Ayende Rahien
 
Ayende Rahien said:
I've a problem in my code using NetworkStream.
I've a server which listen to a port, and then Read() from it, and a
client that send data.
My NetworkStream is wrapped in a CryptoStream, and my problem is that I
don't get all the data that I send.
When I use NetworkStream, all is working properly, but when I use
CryptoStream (initialize to use the NetworkStream), I only get partial data.

Anyone knows why this is happenning?
I would rather avoid using the CryptoStream all-together, but I can't
find any documentation on using TransformBlock & TransformFinalBlock.

In order to see what's wrong, we'll need to see your code.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
Ayende Rahien said:
I attempted to repeat the problem, and run into another one, I'm trying
to send data using CryptoStream wrapping a NetworkStream, the problem
is that while everything works fine if I'm only using NetwrokStream,
using CryptoStream hangs the program.

Yes, I'm not entirely surprised - chances are the write is blocking
because there isn't another thread reading it.

I suspect that your other problem is due to not reading all the data in
one go - generally the situation is that you know in advance how much
data you should have, and you should loop round calling Read until
you've read all the data or you've reached the end of the stream.
 
Jon said:
In order to see what's wrong, we'll need to see your code.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
Jon said:
In order to see what's wrong, we'll need to see your code.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.

I attempted to repeat the problem, and run into another one, I'm trying
to send data using CryptoStream wrapping a NetworkStream, the problem
is that while everything works fine if I'm only using NetwrokStream,
using CryptoStream hangs the program.
Source:

using System;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;

namespace TestCrypto
{

class Class1
{
[STAThread]
static void Main(string[] args)
{
SymmetricAlgorithm sendAlg = SymmetricAlgorithm.Create(),
recieveAlg=SymmetricAlgorithm.Create();
TcpClient client = new TcpClient();
TcpListener listen = new TcpListener(new IPEndPoint(IPAddress.Loopback,1050));
CryptoStream readStream,writeStream;
NetworkStream clientStream,serverStream;
int strLen;
byte [] sendBuffer=System.Text.Encoding.Unicode.GetBytes("This is a test string that I use to see if the stream send everything!"),
recieveBuffer=new byte[1024];
sendAlg.GenerateIV();
sendAlg.GenerateKey();
recieveAlg.IV = sendAlg.IV;
recieveAlg.Key = sendAlg.Key;
listen.Start();
client.Connect("localhost",1050);
clientStream = client.GetStream();
serverStream = listen.AcceptTcpClient().GetStream();
writeStream = new CryptoStream(clientStream,sendAlg.CreateEncryptor(),CryptoStreamMode.Write);
readStream = new CryptoStream(serverStream,recieveAlg.CreateDecryptor(),CryptoStreamMode.Read);
listen.Stop();
//WORKS
clientStream.Write(sendBuffer,0,sendBuffer.Length);
strLen=serverStream.Read(recieveBuffer,0,recieveBuffer.Length);
Console.WriteLine("Unencrypted:");
Console.WriteLine(System.Text.Encoding.Unicode.GetString(recieveBuffer,0,strLen));
//DOESN'T WORK
writeStream.Write(sendBuffer,0,sendBuffer.Length);
strLen=readStream.Read(recieveBuffer,0,recieveBuffer.Length);
Console.WriteLine("Encrypted:");
Console.WriteLine(System.Text.Encoding.Unicode.GetString(recieveBuffer,0,strLen));
}
}
}
 
Jon said:
Yes, I'm not entirely surprised - chances are the write is blocking
because there isn't another thread reading it.

That is not possible. This is a socket connection, not a messaging one.
Using just the NetworkStream *works*.
Beside, considerring that it's supposed to be a Socket underlying all of
this, so it can't block on a *write*.

I suspect that your other problem is due to not reading all the data in
one go - generally the situation is that you know in advance how much
data you should have, and you should loop round calling Read until
you've read all the data or you've reached the end of the stream.

That is the problem, continuing to read result in Read() returning 0
(i.e. no more data).
 
Ayende Rahien said:
That is not possible. This is a socket connection, not a messaging one.
Using just the NetworkStream *works*.
Beside, considerring that it's supposed to be a Socket underlying all of
this, so it can't block on a *write*.

Yes it can - if the receiving end isn't reading, then it may well
block. For instance, try this program:

using System;
using System.Net;
using System.Net.Sockets;

class Test
{
static void Main()
{
TcpClient client = new TcpClient();
TcpListener listen = new TcpListener
(new IPEndPoint(IPAddress.Loopback,1050));

listen.Start();

client.Connect("localhost",1050);
NetworkStream clientStream = client.GetStream();
NetworkStream serverStream =
listen.AcceptTcpClient().GetStream();

byte[] buffer = new byte[1024];
for (int i=0; i < 10000; i++)
{
clientStream.Write(buffer, 0, buffer.Length);
Console.WriteLine("Written {0}K", i+1);
}
}
}

On my box, it blocks after it's written 33K.

Now, why exactly a CryptoStream makes it block earlier, I don't know -
but I'm saying that's possibly the problem.

What you really need is two programs, a simple server and a simple
client - and demonstrate the problem with those.
That is the problem, continuing to read result in Read() returning 0
(i.e. no more data).

Right. Did you call FlushFinalBlock on the writing network stream? (Did
you close it? Closing it *should* call Flush, which will in turn call
FlushFinalBlock, I believe...)
 
Call FlushFinalBlock on your crypto stream to make sure that you flush all of the crypto data. Remember that symmetric algorithms tend to be block-ciphers, which means they must BUFFER your cipher text until they can fill in a full cipher-block. The final block almost ALWAYS is misaligned, so it must pad in the final block (typically with PKCS padding)

CryptoStream.FlushFinalBloc

You will always need to do this with any symmetric crypto algorithm that you use

Hope that helps

-- Jak
 
javatopia said:
Call FlushFinalBlock on your crypto stream to make sure that you flush
all of the crypto data.

But I believe if you're calling Close (or Dispose, which calls Close)
then FlushFinalBlock is called automatically.
 
javatopia said:
Actually, I have found that the call to Close or even Flush does not
actually write the final block.

Flush doesn't write the final block, but I believe Close should, and
Dispose should too.
 
Back
Top