user1309220
user1309220

Reputation: 179

client/server, encrypted comms

I've got a basic tcp client/server setup going in c#. I'm now trying to encrypt the data going back and forth. I'm able to send data from the client to the server, have the server run a command, then try to send the results back to the client. I can get the data from client to server, and the server runs the command. When the server tries to send results back to client I get an error message on the client that the stream is not readable. Below is relevant code parts.

Server:

    .......
//Create an instance of TcpListener to listen for TCP connection.
    TcpListener tcpListener = new TcpListener(IPAddress.Any, TcpPort);
    try
    {
        while (true)
        {
            tcpListener.Start();
            //Accept the client if one is found.
            TcpClient TCP = tcpListener.AcceptTcpClient();
           // Console.WriteLine("Client connected through TCP.");

            //Create a network stream from the connection.
            NetworkStream NetStream = TCP.GetStream();

            //Create a new instance of the RijndaelManaged class
            // and decrypt the stream.
            RijndaelManaged RMCrypto = new RijndaelManaged();


            //Create a CryptoStream, pass it the NetworkStream,  decrypt with the Rijndael class using the key and IV.
            CryptoStream CryptStream = new CryptoStream(NetStream,RMCrypto.CreateDecryptor(Key, IV),CryptoStreamMode.Read);

            //Read the stream.
            StreamReader SReader = new StreamReader(CryptStream);

            //run the command received
            string commandToRun = SReader.ReadToEnd();
            string commandOutput = runCommand(commandToRun);
            Console.WriteLine("output is " + commandOutput);
       //     SReader.Close();

            // now send results back
            CryptoStream CStream_WRITE = new CryptoStream(NetStream, RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);

            if (CStream_WRITE.CanWrite)
            {
                //Create a StreamWriter for easy writing to the network stream.
                StreamWriter SWriter2 = new StreamWriter(CStream_WRITE);

                //Write to the stream.
                SWriter2.Write(commandOutput, commandOutput.Length);
                Console.WriteLine("writing {0} bytes back ", commandOutput.Length);
                SWriter2.Flush();
                SWriter2.Close();
            }

       //       CStream_WRITE.Close();
      //        NetStream.Close();
      //        TCP.Close();
                tcpListener.Stop();

        } // end while
    }
    //Catch any exceptions. 
    catch
    {
        Console.WriteLine("Server Failed");
    }
}

And here is the client: ....... The bold line is where I am getting an error

        //Create a TCP connection to a listening TCP process.

        TcpClient TCP = new TcpClient(serverName, TCPPORT);

        //Create a network stream from the TCP connection. 
        NetworkStream NetStream = TCP.GetStream();

        //Create a new instance of the RijndaelManaged class
        // and encrypt the stream.
        RijndaelManaged RMCrypto = new RijndaelManaged();

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

        //Create a CryptoStream, pass it the NetworkStream, and encrypt 
        //it with the Rijndael class.
        CryptoStream CryptStream = new CryptoStream(NetStream, RMCrypto.CreateEncryptor(Key, IV), CryptoStreamMode.Write);

        if (CryptStream.CanWrite)
        {
            //Create a StreamWriter for easy writing to the network stream.
            StreamWriter SWriter = new StreamWriter(CryptStream);

            //Write to the stream.
            SWriter.WriteLine(theData);
            SWriter.Flush();
            SWriter.Close();
      //    CryptStream.Close();

            //Inform the user that the message was written to the stream.
            Console.WriteLine("The message was sent.");
        }

        // get response
        **CryptoStream CStreamREAD = new CryptoStream(NetStream, RMCrypto.CreateDecryptor(Key, IV), CryptoStreamMode.Read);**
        if (CStreamREAD.CanRead)
        {
            Console.WriteLine("stream can read\n");
            StreamReader SReader = new StreamReader(CStreamREAD);
            string commandResults = SReader.ReadToEnd();
            Console.WriteLine("receiving {0} bytes from server", commandResults.Length);
            Console.WriteLine("results are " + commandResults)

Upvotes: 2

Views: 2562

Answers (2)

Maarten Bodewes
Maarten Bodewes

Reputation: 93968

StreamWriter.close() also closes the underlying stream, which closes CryptoStream, which closes the underlying socket as per API.

At least, that'm my guess as experienced Java developer :)

Upvotes: 0

mfanto
mfanto

Reputation: 14418

The easiest, and BY FAR the safest, is to implement an already existing protocol, like SSL. You can use the SslStream class to provide security and server authentication, or you can just switch to WCF and not deal with streams at all. Here is a question on how to enable SSL for WCF. As for just a basic WCF tutorial, there are hundreds.

Rolling your own is likely to be very insecure and error prone.

Upvotes: 4

Related Questions