using System; using System.Text; using System.IO; using System.Net.Sockets; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography;
namespace com.billdawson.crypto { /// <summary> /// Test client for showing .NET crypto over sockets. /// </summary> /// <remarks> /// Please note that this is a highly contrived, artificial /// and not robust sockets application. For example, the server /// assumes that the client sends all the right stuff in the /// right order, one after the other, without any error checks. /// /// /// Usage: /// >cryptoclient [host] [port] /// /// Steps: /// * Connect to host and port /// * Immediately send public RSA key /// * Receive in succession: /// * Encrypted Symmetric Key and IV /// * Encrypted secret message /// * Decrypt secret message and display /// </remarks> public class CryptoClient { private const string USAGE = "USAGE:\n" + "cryptoclient [host] [port]"; private const int RSA_KEY_SIZE_BITS = 1024; private const int RSA_KEY_SIZE_BYTES = 252; private const int TDES_KEY_SIZE_BITS = 192; private const int TDES_KEY_SIZE_BYTES = 128; private const int TDES_IV_SIZE_BYTES = 128; public static void Main(string[] args) { int port; string host; TcpClient client; SymmetricAlgorithm symm; RSACryptoServiceProvider rsa; if (args.Length!=2) { Console.WriteLine(USAGE); return; } try // parsing arguments { host = args[0]; port = Int32.Parse(args[1]); } catch { Console.WriteLine(USAGE); return; } try // connecting { client = new TcpClient(); client.Connect(host,port); } catch(Exception e) { Console.WriteLine(e.Message); Console.Write(e.StackTrace); return; } try // everything else { Console.WriteLine("Connected. Sending public key."); rsa = new RSACryptoServiceProvider(); rsa.KeySize = RSA_KEY_SIZE_BITS; sendPublicKey(rsa.ExportParameters(false),client); symm = new TripleDESCryptoServiceProvider(); symm.KeySize = TDES_KEY_SIZE_BITS; MemoryStream ms = getRestOfMessage(client); extractSymmetricKeyInfo(rsa, symm, ms); showSecretMessage(symm, ms); } catch(Exception e) { Console.WriteLine(e.Message); Console.Write(e.StackTrace); } finally { try { client.Close(); } catch { // ignore } } } // end Main private static void sendPublicKey( RSAParameters key, TcpClient client) { NetworkStream ns = client.GetStream(); BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(ns,key); } // end sendPublicKey
private static MemoryStream getRestOfMessage(TcpClient client) { // This ends up getting the symmetric key, // the symmetric IV, and the secret message, all encrypted. // The symmetric key is encrypted with this client's // public RSA key. The secret message is encrypted // with the symmetric key. MemoryStream ms = new MemoryStream(); NetworkStream ns = client.GetStream(); byte[] buffer = new byte[1024]; int len=0;
// Put everything from the NetStream into // a memory stream. while((len = ns.Read(buffer, 0, buffer.Length))>0) {
ms.Write(buffer, 0, len); } ms.Position = 0; return ms; } // end getRestOfMsg private static void extractSymmetricKeyInfo( RSACryptoServiceProvider rsa, SymmetricAlgorithm symm, MemoryStream msOrig) { MemoryStream ms = new MemoryStream();
// get the TDES Key -- encrypted by host // with our RSA Public Key -- // and decrypt using our private key. byte[] buffer = new byte[TDES_KEY_SIZE_BYTES]; msOrig.Read(buffer,0,buffer.Length); symm.Key = rsa.Decrypt(buffer,false); // get the TDES IV -- encrypted by host // with our RSA Public Key -- // and decrypt using our private key. buffer = new byte[TDES_IV_SIZE_BYTES]; msOrig.Read(buffer, 0, buffer.Length); symm.IV = rsa.Decrypt(buffer,false); } // end extractSymmetricKeyInfo private static void showSecretMessage( SymmetricAlgorithm symm, MemoryStream msOrig) { // Everything left in the memory stream (from its position) // is an encrypted, ASCII-encoded secret message byte[] buffer = new byte[1024]; int len = msOrig.Read(buffer,0,buffer.Length); MemoryStream ms = new MemoryStream(); ICryptoTransform transform = symm.CreateDecryptor(symm.Key,symm.IV); CryptoStream cstream = new CryptoStream(ms, transform, CryptoStreamMode.Write); cstream.Write(buffer, 0, len); cstream.FlushFinalBlock(); // The memory stream ms now has the secret message // decrypted, but as bytes. Change to a string ms.Position = 0; len = ms.Read(buffer,0,(int) ms.Length); ms.Close(); string msg = Encoding.ASCII.GetString(buffer,0,len); Console.WriteLine("The host sent me this secret message:"); Console.WriteLine(msg);
} // end showSecretMessage } // end class CryptoClient } // end namespace |