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 TCP server (synchronous) to show .NET symmetric and /// asymmetric encryption features. /// </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: /// >cryptoserver [port] [secret message] /// The secret message is what will be encrypted and sent to the /// client. If you put whitespace in the secret message as /// a command-line arg, be sure to enclose it in quotes. /// /// Steps: /// * Open TCP Port,listen, accept client /// * Wait for 252 byte serialization of client's RSA public key /// * Use that to encrypt a TripleDES Key and IV /// * Send those back to the client /// * Use the TripleDES Key and IV to encrypt the secret message /// * Send secret message to client. /// </remarks>
public class CryptoServer { private const string USAGE = "USAGE:\n" + "cryptoserver [port] [secret message]\n\n" + "If secret message has whitespace, " + "enclose in quotes."; private const int RSA_KEY_SIZE_BITS = 1024; private const int RSA_KEY_SIZE_BYTES = 252; private const int TDES_KEY_SIZE_BITS = 192; public static void Main(string[] args) { int port; string msg; TcpListener listener; TcpClient client; SymmetricAlgorithm symm; RSACryptoServiceProvider rsa; if (args.Length!=2) { Console.WriteLine(USAGE); return; } try { port = Int32.Parse(args[0]); msg = args[1]; } catch { Console.WriteLine(USAGE); return; } try { listener = new TcpListener(port); listener.Start(); Console.WriteLine("Listening on port {0}...",port); client = listener.AcceptTcpClient(); Console.WriteLine("connection...."); } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); return; } try { rsa = new RSACryptoServiceProvider(); rsa.KeySize = RSA_KEY_SIZE_BITS; // Set the client public key rsa.ImportParameters(getClientPublicKey(client)); symm = new TripleDESCryptoServiceProvider(); symm.KeySize = TDES_KEY_SIZE_BITS; // encrypt the Symmetric Key info using // client's RSA public key, and send it to client encryptAndSendSymmetricKey(client, rsa, symm); // Encrypt the secret message using the // symmetric key, and send it encryptAndSendSecretMessage(client, symm, msg); } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } finally { // Try to clean up. put in try...catch just // in case some of these things never opened try { client.Close(); listener.Stop(); } catch { // Ignore } Console.WriteLine("Server exiting..."); } } // end Main private static RSAParameters getClientPublicKey(TcpClient client) { // Get the serialized public key from the byte stream. // Deserialize it into its class instance // We know it's 252 bytes (hard-coded! not robust!) byte[] buffer = new byte[RSA_KEY_SIZE_BYTES]; NetworkStream ns = client.GetStream(); MemoryStream ms = new MemoryStream(); BinaryFormatter bf = new BinaryFormatter(); RSAParameters result; int len = 0; int totalLen = 0; while(totalLen<RSA_KEY_SIZE_BYTES && (len = ns.Read(buffer,0,buffer.Length))>0) { totalLen+=len; ms.Write(buffer, 0, len); } ms.Position=0; // reposition so binary formatter can read all of it result = (RSAParameters)bf.Deserialize(ms); ms.Close(); return result; } // end getClientPublicKey private static void encryptAndSendSymmetricKey( TcpClient client, RSACryptoServiceProvider rsa, SymmetricAlgorithm symm) { // Using client's public key, encrypt the // symmetric key we'll be using for subsequent // messages and send to client. byte[] symKeyEncrypted; byte[] symIVEncrypted; NetworkStream ns = client.GetStream(); symKeyEncrypted = rsa.Encrypt(symm.Key, false); symIVEncrypted = rsa.Encrypt(symm.IV, false); ns.Write(symKeyEncrypted, 0, symKeyEncrypted.Length); ns.Write(symIVEncrypted, 0, symIVEncrypted.Length); } // end encryptAndSendSymmetricKey
private static void encryptAndSendSecretMessage( TcpClient client, SymmetricAlgorithm symm, string secretMsg) { // Using the symmetric key and initialization vector, // Eencrypt the secret message and send to client. byte[] msgAsBytes; NetworkStream ns = client.GetStream(); ICryptoTransform transform = symm.CreateEncryptor(symm.Key,symm.IV); CryptoStream cstream = new CryptoStream(ns, transform, CryptoStreamMode.Write); // First get the secretMsg into bytes msgAsBytes = Encoding.ASCII.GetBytes(secretMsg); cstream.Write(msgAsBytes, 0, msgAsBytes.Length); cstream.FlushFinalBlock(); } // end encryptAndSendSecretMessage }// end class CryptoServer }// end namespace |