3

This concept seems simple enough: Create two separate applications, send encrypted text from the client to the server, then send a reply from the server to the client- I assumed that I could simply establish a TcpClient connection between the two, get a NetworkStream, and use two CryptoStreams on that NetworkStream(one for read & one for write). However, in my examples below(which are largely based on the MSDN example), text can be encrypted, sent to the server, decrypted and displayed just fine, but when the server attempts to reply, it throws "Unable to write data to the transport connection...". Maybe the underlying stream is getting closed when the StreamWriter is closed? By the way, this concept works perfectly fine when sending unencrypted text over the NetworkStream itself, as NetworkStreams are natively bi-directional.

EDIT: It seems that closing the CryptoStream results in everything else being closed as well. If I manually call sendReply() on the server after the client has sent a message, the server will reply successfully(as long as the NetworkStream has not been closed on the client). Then the server will throw "Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall." at SReader.Readline. Multiple CryptoStreams seem to work, so maybe the real problem is that the server doesn't know when to stop reading. I'm not sure how to remedy that either. Adding "\r\n" to the message and using ReadLine() don't seem to help.

Server:

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 };

Thread listener;
NetworkStream nwStream;
TcpClient client;

RijndaelManaged RMCrypto;
CryptoStream CryptStreamRead;
CryptoStream CryptStreamWrite;
StreamReader SReader;
StreamWriter SWriter;

private void Form1_Load(object sender, EventArgs e)
{
    listener = new Thread(new ThreadStart(tcpListen));
    listener.IsBackground = true;
    listener.Start();
}

private void tcpListen()
{
    int port = 7777;
    string dataReceived;

    TcpListener listener = new TcpListener(IPAddress.Any, port);
    listener.Start();

    while (true)
    {
        client = listener.AcceptTcpClient();
        nwStream = client.GetStream();

        RMCrypto = new RijndaelManaged();
        CryptStreamRead = new CryptoStream(nwStream, RMCrypto.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
        SReader = new StreamReader(CryptStreamRead);

        string received = SReader.ReadLine();
        Invoke(new MethodInvoker(() => textBoxReceived.Text = received));
        Invoke(new MethodInvoker(() => sendReply("REPLY: " + received)));

        //SReader.Close();
        //CryptStreamRead.Close();
        //nwStream.Close();
        //client.Close();

        //listener.Stop();
    }
}

private void sendReply(string input)
{
    try
    {
        CryptStreamWrite = new CryptoStream(nwStream, RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
        SWriter = new StreamWriter(CryptStreamWrite);
        SWriter.WriteLine(input);
        SWriter.Flush();

        SWriter.Close();
        CryptStreamWrite.Close();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
} 

Client:

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 };

int port = 7777;
string serverIP = "127.0.0.1";
TcpClient client;
NetworkStream nwStream;

RijndaelManaged RMCrypto;
CryptoStream CryptStreamWrite;
CryptoStream CryptStreamRead;
StreamWriter SWriter;
StreamReader SReader;

private void sendToServer(string input)
{
    try
    {
        string textToSend = textBoxToSend.Text;

        client = new TcpClient(serverIP, port);
        nwStream = client.GetStream();
        RMCrypto = new RijndaelManaged();
        //CryptoStream CryptStream = new CryptoStream(nwStream,RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
        CryptStreamWrite = new CryptoStream(nwStream, RMCrypto.CreateEncryptor(Key, IV)), CryptoStreamMode.Write);
        SWriter = new StreamWriter(CryptStreamWrite);
        SWriter.WriteLine(textBoxToSend.Text);
        SWriter.Flush();

        SWriter.Close();
        CryptStreamWrite.Close();
        //nwStream.Close();
        //client.Close();

        waitForResponse();
    }
    catch
    {
        textBoxReceived.Text = "Cannot Create Connection to Server";
    }
}

private void waitForResponse()
{
    try
    {
        CryptStreamRead = new CryptoStream(nwStream, RMCrypto.CreateDecryptor(CalculateMD5Hash(textBoxKey.Text), CalculateMD5Hash(textBoxKey.Text)), CryptoStreamMode.Read);
        SReader = new StreamReader(CryptStreamRead);
        textBoxReceived.Text = SReader.ReadLine();

        SReader.Close();
        CryptStreamRead.Close();
        nwStream.Close();
        client.Close();
    }
    catch
    {
        textBoxReceived.Text = "No Response From Server";
    }
}
  • Instead of using a `CryptoStream` you may want to switch to using a [`SslStream`](http://msdn.microsoft.com/en-us/library/system.net.security.sslstream%28v=vs.110%29.aspx) which is specifically designed to work with the `TcpClient` class. – Scott Chamberlain Mar 17 '14 at 23:53
  • @ScottChamberlain I had considered `SslStream` initially, but it seemed overcomplicated for what I'm trying to do. Plus, I would prefer not to have to mess with certificates, etc. – code2control Mar 18 '14 at 15:57

0 Answers0