I'm having problems with cryptography and sockets, help

  • Thread starter Thread starter Alejandro Castañaza
  • Start date Start date
A

Alejandro Castañaza

Hi.

I'm writing a program, and I need to send confidential data through the
network, so I decided to use encryption, using the
System.Security.Cryptography namespace.

I'm using the sockets for the network communications, and the program first
does a key exchange, with the asymetric cipher classes, to get a new key for
the symmetric cipher. My problem is, that although I have checked that the
two points get to the same key and initialization vector, when the sender
sends the data, its ok, but the receiver gets blocked. I am using blocking
sockets, so I am aware that if the socket does not have received data, it
blocks until it does. But I know that it does receive the data, and still
it blocks, not the NetworkStream, but the CryptoStream used to decrypt the
data. I have been trying many things, using the StreamReader and
StreamWriter like in the documentation examples, but doesn't work.

I need help, please. It's been 2 full days trying, please help.

Alejandro.



Here are some lines of the code:

This is the receiver code (where it blocks, in the Read function):

string mensaje;
NetworkStream stream = clienteTcp.GetStream();
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateDecryptor(tdesClave,tdesIV),
CryptoStreamMode.Read);
// Búfer de 8Kb
byte[] datos = new byte[8192];
int bytes;
int intentos = 25;
// Detectar si hay datos
while(intentos > 0)
{
if (stream.DataAvailable)
break;
intentos--;
System.Threading.Thread.Sleep(200);
}
// Si no hay datos salir
if (!stream.DataAvailable)
return String.Empty;
// Leer mensaje
bytes = crStream.Read(datos,0,datos.Length);
// Pasar a string
mensaje = System.Text.Encoding.Unicode.GetString(datos,0,bytes);


This is the sender code:

NetworkStream stream = new NetworkStream(clienteTcp);
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateEncryptor(tdesClave,tdesIV),
CryptoStreamMode.Write);
// Convertir el string a una matriz de bytes
byte[] datos = System.Text.Encoding.Unicode.GetBytes(mensaje);
// Transmitir mensaje
crStream.Write(datos,0,datos.Length);
crStream.Flush();
 
Alejandro,

It looks like you are trying to read too much data. You are issuing a
call to the Read method on the socket class passing in a length of 8192
bytes. If the sender does not send 8192 bytes, the call to Read is going to
block until it gets 8192 bytes.

There are two ways of handling this. The first is to mark your message
with an identifier which indicates that the message has completed
transmission. This would require you to read byte-by-byte, which is not a
good thing.

The second is to actually send the length of the message before you send
the message yourself. This way, you can issue a call to the Read method and
know you are not asking for more data than is on the line.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Alejandro Castañaza said:
Hi.

I'm writing a program, and I need to send confidential data through the
network, so I decided to use encryption, using the
System.Security.Cryptography namespace.

I'm using the sockets for the network communications, and the program
first does a key exchange, with the asymetric cipher classes, to get a new
key for the symmetric cipher. My problem is, that although I have checked
that the two points get to the same key and initialization vector, when
the sender sends the data, its ok, but the receiver gets blocked. I am
using blocking sockets, so I am aware that if the socket does not have
received data, it blocks until it does. But I know that it does receive
the data, and still it blocks, not the NetworkStream, but the CryptoStream
used to decrypt the data. I have been trying many things, using the
StreamReader and StreamWriter like in the documentation examples, but
doesn't work.

I need help, please. It's been 2 full days trying, please help.

Alejandro.



Here are some lines of the code:

This is the receiver code (where it blocks, in the Read function):

string mensaje;
NetworkStream stream = clienteTcp.GetStream();
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateDecryptor(tdesClave,tdesIV),

CryptoStreamMode.Read);
// Búfer de 8Kb
byte[] datos = new byte[8192];
int bytes;
int intentos = 25;
// Detectar si hay datos
while(intentos > 0)
{
if (stream.DataAvailable)
break;
intentos--;
System.Threading.Thread.Sleep(200);
}
// Si no hay datos salir
if (!stream.DataAvailable)
return String.Empty;
// Leer mensaje
bytes = crStream.Read(datos,0,datos.Length);
// Pasar a string
mensaje = System.Text.Encoding.Unicode.GetString(datos,0,bytes);


This is the sender code:

NetworkStream stream = new NetworkStream(clienteTcp);
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateEncryptor(tdesClave,tdesIV),
CryptoStreamMode.Write);
// Convertir el string a una matriz de bytes
byte[] datos = System.Text.Encoding.Unicode.GetBytes(mensaje);
// Transmitir mensaje
crStream.Write(datos,0,datos.Length);
crStream.Flush();
 
Thank you Nicholas.
The receiver routine I wrote for receiving plain data is almost the same,
only that it calls Read in the NetworkStream object instead of the
CryptoStream, with the same length of 8192 bytes, and it doesn't block, and
returns the number of bytes actually read.

Is the CryptoStream different to the NetworkStream in this matter?


Nicholas Paldino said:
Alejandro,

It looks like you are trying to read too much data. You are issuing a
call to the Read method on the socket class passing in a length of 8192
bytes. If the sender does not send 8192 bytes, the call to Read is going
to block until it gets 8192 bytes.

There are two ways of handling this. The first is to mark your message
with an identifier which indicates that the message has completed
transmission. This would require you to read byte-by-byte, which is not a
good thing.

The second is to actually send the length of the message before you
send the message yourself. This way, you can issue a call to the Read
method and know you are not asking for more data than is on the line.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Alejandro Castañaza said:
Hi.

I'm writing a program, and I need to send confidential data through the
network, so I decided to use encryption, using the
System.Security.Cryptography namespace.

I'm using the sockets for the network communications, and the program
first does a key exchange, with the asymetric cipher classes, to get a
new key for the symmetric cipher. My problem is, that although I have
checked that the two points get to the same key and initialization
vector, when the sender sends the data, its ok, but the receiver gets
blocked. I am using blocking sockets, so I am aware that if the socket
does not have received data, it blocks until it does. But I know that it
does receive the data, and still it blocks, not the NetworkStream, but
the CryptoStream used to decrypt the data. I have been trying many
things, using the StreamReader and StreamWriter like in the documentation
examples, but doesn't work.

I need help, please. It's been 2 full days trying, please help.

Alejandro.



Here are some lines of the code:

This is the receiver code (where it blocks, in the Read function):

string mensaje;
NetworkStream stream = clienteTcp.GetStream();
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateDecryptor(tdesClave,tdesIV),

CryptoStreamMode.Read);
// Búfer de 8Kb
byte[] datos = new byte[8192];
int bytes;
int intentos = 25;
// Detectar si hay datos
while(intentos > 0)
{
if (stream.DataAvailable)
break;
intentos--;
System.Threading.Thread.Sleep(200);
}
// Si no hay datos salir
if (!stream.DataAvailable)
return String.Empty;
// Leer mensaje
bytes = crStream.Read(datos,0,datos.Length);
// Pasar a string
mensaje = System.Text.Encoding.Unicode.GetString(datos,0,bytes);


This is the sender code:

NetworkStream stream = new NetworkStream(clienteTcp);
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateEncryptor(tdesClave,tdesIV),
CryptoStreamMode.Write);
// Convertir el string a una matriz de bytes
byte[] datos = System.Text.Encoding.Unicode.GetBytes(mensaje);
// Transmitir mensaje
crStream.Write(datos,0,datos.Length);
crStream.Flush();
 
By the way...
Is there a method to convert an int to an array of bytes?



Nicholas Paldino said:
Alejandro,

It looks like you are trying to read too much data. You are issuing a
call to the Read method on the socket class passing in a length of 8192
bytes. If the sender does not send 8192 bytes, the call to Read is going
to block until it gets 8192 bytes.

There are two ways of handling this. The first is to mark your message
with an identifier which indicates that the message has completed
transmission. This would require you to read byte-by-byte, which is not a
good thing.

The second is to actually send the length of the message before you
send the message yourself. This way, you can issue a call to the Read
method and know you are not asking for more data than is on the line.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Alejandro Castañaza said:
Hi.

I'm writing a program, and I need to send confidential data through the
network, so I decided to use encryption, using the
System.Security.Cryptography namespace.

I'm using the sockets for the network communications, and the program
first does a key exchange, with the asymetric cipher classes, to get a
new key for the symmetric cipher. My problem is, that although I have
checked that the two points get to the same key and initialization
vector, when the sender sends the data, its ok, but the receiver gets
blocked. I am using blocking sockets, so I am aware that if the socket
does not have received data, it blocks until it does. But I know that it
does receive the data, and still it blocks, not the NetworkStream, but
the CryptoStream used to decrypt the data. I have been trying many
things, using the StreamReader and StreamWriter like in the documentation
examples, but doesn't work.

I need help, please. It's been 2 full days trying, please help.

Alejandro.



Here are some lines of the code:

This is the receiver code (where it blocks, in the Read function):

string mensaje;
NetworkStream stream = clienteTcp.GetStream();
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateDecryptor(tdesClave,tdesIV),

CryptoStreamMode.Read);
// Búfer de 8Kb
byte[] datos = new byte[8192];
int bytes;
int intentos = 25;
// Detectar si hay datos
while(intentos > 0)
{
if (stream.DataAvailable)
break;
intentos--;
System.Threading.Thread.Sleep(200);
}
// Si no hay datos salir
if (!stream.DataAvailable)
return String.Empty;
// Leer mensaje
bytes = crStream.Read(datos,0,datos.Length);
// Pasar a string
mensaje = System.Text.Encoding.Unicode.GetString(datos,0,bytes);


This is the sender code:

NetworkStream stream = new NetworkStream(clienteTcp);
// Crear el stream criptográfico
CryptoStream crStream = new
CryptoStream(stream,TDES.CreateEncryptor(tdesClave,tdesIV),
CryptoStreamMode.Write);
// Convertir el string a una matriz de bytes
byte[] datos = System.Text.Encoding.Unicode.GetBytes(mensaje);
// Transmitir mensaje
crStream.Write(datos,0,datos.Length);
crStream.Flush();
 
Thank you. I was writing my own method already. This is what I like about
..NET! you don't have to waste time writing this kind of things!

"Jon Skeet [C# MVP]" <[email protected]> escribió en el mensaje
Alejandro Castañaza said:
By the way...
Is there a method to convert an int to an array of bytes?

Look at BitConverter.GetBytes.
 
I tried your second sugestion, sending first the length of the message, then
call Read with that number, but it still blocks. It reads the length but
the call to cryptoStream.Read still blocks. Please help!
 
At last! Solved the problem.

I used the cryptostream object in the receiver to write to a memorystream
instead of reading the networkstream, and it worked.

Seems like the cryptostream won't read from a networkstream. A .net bug?

Thank you all very much for your help.

Alejandro.



Alejandro Castañaza said:
I tried your second sugestion, sending first the length of the message,
then call Read with that number, but it still blocks. It reads the length
but the call to cryptoStream.Read still blocks. Please help!
 
Alejandro Castañaza said:
At last! Solved the problem.

I used the cryptostream object in the receiver to write to a memorystream
instead of reading the networkstream, and it worked.

Seems like the cryptostream won't read from a networkstream. A .net bug?

Unlikely. I use CryptoStreams every day over NetworkStreams.

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.

By the way, in your original code I notice you aren't calling
FlushFinalBlock on the CryptoStream - are you doing that in your real
code?
 
Jon
I made many changes to the original code after I posted, because I was still
trying to make it work. Then I added the call to FlushFinalBlock, but the
Read call still blocked. Then I used the streamReader, ReadToEnd and
blocked. Then, after looking some example code for encryption, I tried the
solution I wrote earlier, using the cryptostream object to write to a temp
memorystream, and reading the plain text from it. Its working that way.

I didn't mean to say for sure it is a bug. Since the first message I asked
for help, because I thought maybe I was missing something (like the call to
flushfinalblock) or was doing something wrong.

I havent tried, but after I finally made it work, I thought that the problem
was because encryption always expand a little the original block of data,
and that was why I was having trouble with it. That is the reason to call
FlushFinalBlock or close the cryptostream, right? so it can finish the
encryption process and send the last block of encrypted data. So maybe I
have to try reading the networkstream using the cryptostream with this
concept in mind. But I'll do it later. Its working now, and I have so much
to do still about that program.

I appreciate your comments.

Alejandro.


"Jon Skeet [C# MVP]" <[email protected]> escribió en el mensaje
Alejandro Castañaza said:
At last! Solved the problem.

I used the cryptostream object in the receiver to write to a memorystream
instead of reading the networkstream, and it worked.

Seems like the cryptostream won't read from a networkstream. A .net bug?

Unlikely. I use CryptoStreams every day over NetworkStreams.

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.

By the way, in your original code I notice you aren't calling
FlushFinalBlock on the CryptoStream - are you doing that in your real
code?
 
Alejandro Castañaza said:
I made many changes to the original code after I posted, because I was still
trying to make it work. Then I added the call to FlushFinalBlock, but the
Read call still blocked. Then I used the streamReader, ReadToEnd and
blocked. Then, after looking some example code for encryption, I tried the
solution I wrote earlier, using the cryptostream object to write to a temp
memorystream, and reading the plain text from it. Its working that way.

I didn't mean to say for sure it is a bug. Since the first message I asked
for help, because I thought maybe I was missing something (like the call to
flushfinalblock) or was doing something wrong.

I havent tried, but after I finally made it work, I thought that the problem
was because encryption always expand a little the original block of data,
and that was why I was having trouble with it. That is the reason to call
FlushFinalBlock or close the cryptostream, right? so it can finish the
encryption process and send the last block of encrypted data.

Not only that - but so it can then tell the stream that it's finished,
so that things like ReadToEnd will complete. If you leave the stream
open, things like ReadToEnd won't know whether there might be some more
data to come or not.
So maybe I have to try reading the networkstream using the
cryptostream with this concept in mind. But I'll do it later. Its
working now, and I have so much to do still about that program.

Fair enough. If you do find out what was wrong, please report back to
the group :)
 
Back
Top