0

I'm trying to encrypt data that I send over a TCP connection, however, I'm not receiving any data through my CryptoStream.

Here is the class where I set up the streams:

public class SecureCommunication
{
    public SecureCommunication(TcpClient client, byte[] key, byte[] iv)
    {
        _client = client;

        _netStream = _client.GetStream();

        var rijndael = new RijndaelManaged();
        _cryptoReader = new CryptoStream(_netStream, 
            rijndael.CreateEncryptor(key, iv), CryptoStreamMode.Read);
        _cryptoWriter = new CryptoStream(_netStream, 
            rijndael.CreateEncryptor(key, iv), CryptoStreamMode.Write);

        _reader = new StreamReader(_cryptoReader);
        _writer = new StreamWriter(_cryptoWriter);
    }

    public string Receive()
    {
        return _reader.ReadLine();
    }

    public void Send(string buffer)
    {
        _writer.WriteLine(buffer);
        _writer.Flush();
    }

    ...

The key and init vector:

byte[] iv = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
byte[] key = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };

On my test client program I call

var client = new TcpClient("xxx.xxx.xxx.xxx", 12345);
var communication = new SecureTcpCommunication(client, key, iv);
communication.Send("Test message");

And on my server I call:

var serverSocket = new TcpListener(IPAddress.Any, tcpPort);
var client = serverSocket.AcceptTcpClient();
var communication = new SecureTcpCommunication(client, key, iv);
Console.WriteLine($"Received message: {communication.Receive()}");

However the application blocks on communication.Receive and never finishes. What am I doing wrong here? I feel like its something really simple..

flakes
  • 21,558
  • 8
  • 41
  • 88
  • `StringReader` and `StringWriter` don't work very well with network streams, and the crypto stream isn't making this any easier. Have you considered just using SSL? – Luaan Jul 18 '16 at 15:19
  • @Luaan I think that's what I'm going to do in the long run. Just curious why this doesn't work at this point. Maybe if I turned the messages into a base64 string first? – flakes Jul 18 '16 at 15:43
  • 1
    Buffering. Sadly, the `Flush` isn't quite enough to make everything wrong properly. You'll note that right now, even if you do a plain `ReadByte` on the network stream, you hang. However, make the message longer, and at some point, you'll be able to read *something*, though still not enough for the `ReadLine`. The truth is, networking is quite complicated, and the abstractions don't always work very well, and the same is true for cryptostreams. And strings, really. Abstractions leak :D – Luaan Jul 18 '16 at 17:04
  • @Luaan weird! Any idea if this [msdn](https://msdn.microsoft.com/en-us/library/as0w18af(v=vs.110).aspx) article is at all accurate? That's where I got the idea. – flakes Jul 18 '16 at 17:15
  • 2
    The article closes the stream after a single message, that is flushing the data completely. You don't close the stream so pending blocks are still waiting for more data so it can be encrypted in to a complete block. Switch over to a `SslStream` object, it will make it much easier because it handles stuff like flushing a message even though you don't have a complete block for you. – Scott Chamberlain Jul 18 '16 at 18:14
  • 1
    Scott said it. Also, it's not exactly exceptional for MSDN samples to be misleading or outright wrong either - and a lot of the time, very dated. And they're just very short, straightforward samples that don't deal with error handling - the real world is a lot more complicated regardless. TCP is still a very low level protocol, and needs a lot of care. – Luaan Jul 19 '16 at 07:33

1 Answers1

0

In your send function, call _cryptoWriter.Flush() last. _writer.Flush() doesn't call flush on the encapsulated stream.

Kind Contributor
  • 17,547
  • 6
  • 53
  • 70