MTSC  1.0.5
Build TCP servers out of modules with handlers for communication, exception and logging.
EncryptionHandler.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Security.Cryptography;
5 using System.Text;
6 using MTSC;
7 
8 namespace MTSC.Server.Handlers
9 {
13  public class EncryptionHandler : IHandler
14  {
15  private enum ClientState
16  {
17  Initial,
18  Negotiating,
19  Encrypted
20  }
21  private class AdditionalData
22  {
23  public byte[] Key;
24  public ClientState ClientState = ClientState.Initial;
25  }
26  #region Fields
27  private Dictionary<ClientData, AdditionalData> additionalData;
28  private RSACryptoServiceProvider rsa;
29  private string privateKey, publicKey;
30  #endregion
31  #region Properties
32  #endregion
33  #region Constructors
34  public EncryptionHandler(RSACryptoServiceProvider rsa)
40  {
41  additionalData = new Dictionary<ClientData, AdditionalData>();
42  this.rsa = rsa;
43  privateKey = HelperFunctions.ToXmlString(rsa, true);
44  publicKey = HelperFunctions.ToXmlString(rsa, false);
45  }
46  #endregion
47  #region Public Methods
48 
49  #endregion
50  #region Private Methods
51  private byte[] EncryptBytes(byte[] clientKey, byte[] bytesToBeEncrypted)
52  {
53  byte[] encryptedBytes = null;
54 
55  // Set your salt here, change it to meet your flavor:
56  // The salt bytes must be at least 8 bytes.
57  byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
58 
59  using (MemoryStream ms = new MemoryStream())
60  {
61  using (RijndaelManaged AES = new RijndaelManaged())
62  {
63  AES.KeySize = 256;
64  AES.BlockSize = 128;
65 
66  AES.Mode = CipherMode.CBC;
67 
68  var key = new Rfc2898DeriveBytes(clientKey, saltBytes, 1000);
69  AES.Key = key.GetBytes(AES.KeySize / 8);
70  AES.IV = key.GetBytes(AES.BlockSize / 8);
71 
72 
73 
74  using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
75  {
76  cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
77  cs.Close();
78  }
79  encryptedBytes = ms.ToArray();
80  }
81  }
82 
83  return encryptedBytes;
84  }
85 
86  private byte[] DecryptBytes(byte[] clientKey, byte[] bytesToBeDecrypted)
87  {
88  byte[] decryptedBytes = null;
89 
90  // Set your salt here, change it to meet your flavor:
91  // The salt bytes must be at least 8 bytes.
92  byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
93 
94  using (MemoryStream ms = new MemoryStream())
95  {
96  using (RijndaelManaged AES = new RijndaelManaged())
97  {
98  AES.KeySize = 256;
99  AES.BlockSize = 128;
100 
101  AES.Mode = CipherMode.CBC;
102 
103  var key = new Rfc2898DeriveBytes(clientKey, saltBytes, 1000);
104  AES.Key = key.GetBytes(AES.KeySize / 8);
105  AES.IV = key.GetBytes(AES.BlockSize / 8);
106 
107 
108 
109  using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
110  {
111  cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
112  cs.Close();
113  }
114  decryptedBytes = ms.ToArray();
115  }
116  }
117 
118  return decryptedBytes;
119  }
120  #endregion
121  #region Handler Implementation
122  void IHandler.ClientRemoved(Server server, ClientData client)
127  {
128  additionalData.Remove(client);
129  }
135  bool IHandler.HandleClient(Server server, ClientData client)
136  {
137  additionalData.Add(client, new AdditionalData());
138  return false;
139  }
146  bool IHandler.HandleReceivedMessage(Server server, ClientData client, Message message)
147  {
148  if (additionalData[client].ClientState == ClientState.Initial || additionalData[client].ClientState == ClientState.Negotiating)
149  {
150  string asciiMessage = ASCIIEncoding.ASCII.GetString(message.MessageBytes);
151  if (asciiMessage == CommunicationPrimitives.RequestPublicKey)
152  {
153  server.QueueMessage(client, ASCIIEncoding.ASCII.GetBytes(CommunicationPrimitives.SendPublicKey + ":" + publicKey));
154  additionalData[client].ClientState = ClientState.Negotiating;
155  return true;
156  }
157  else if (asciiMessage.Contains(CommunicationPrimitives.SendEncryptionKey))
158  {
159  byte[] encryptedKey = new byte[message.MessageLength - CommunicationPrimitives.SendEncryptionKey.Length - 1];
160  Array.Copy(message.MessageBytes, CommunicationPrimitives.SendEncryptionKey.Length + 1, encryptedKey, 0, encryptedKey.Length);
161  byte[] decryptedKey = rsa.Decrypt(encryptedKey, false);
162  additionalData[client].Key = decryptedKey;
163  server.QueueMessage(client, ASCIIEncoding.ASCII.GetBytes(CommunicationPrimitives.AcceptEncryptionKey));
164  additionalData[client].ClientState = ClientState.Encrypted;
165  return true;
166  }
167  else
168  {
169  return false;
170  }
171  }
172  else
173  {
174  return false;
175  }
176  }
183  bool IHandler.PreHandleReceivedMessage(Server server, ClientData client, ref Message message)
184  {
185  if (additionalData[client].ClientState == ClientState.Encrypted)
186  {
187  /*
188  * Decrypt message before returning.
189  */
190  byte[] encryptedBytes = message.MessageBytes;
191  byte[] decryptedBytes = DecryptBytes(additionalData[client].Key, encryptedBytes);
192  message = new Message((uint)decryptedBytes.Length, decryptedBytes);
193  return false;
194  }
195  else
196  {
197  /*
198  * If the state of the client is not encrypted, there's nothing to decrypt.
199  */
200  return false;
201  }
202  }
206  void IHandler.Tick(Server server)
207  {
208 
209  }
216  bool IHandler.HandleSendMessage(Server server, ClientData client, ref Message message)
217  {
218  if (additionalData[client].ClientState == ClientState.Encrypted)
219  {
220  message = CommunicationPrimitives.BuildMessage(EncryptBytes(additionalData[client].Key, message.MessageBytes));
221  }
222  return false;
223  }
224  #endregion
225  }
226 }
Interface for communication handlers.
Definition: IHandler.cs:11
bool PreHandleReceivedMessage(Server server, ClientData client, ref Message message)
Called before the message handling. Perform here any processing of the message.
Structure containing client information.
Definition: Server.cs:402
Handler that encrypts the communication.
void QueueMessage(ClientData target, byte[] message)
Queues a message to be sent.
Definition: Server.cs:137
void ClientRemoved(Server server, ClientData client)
Handles the removal of a client from the server.
void Tick(Server server)
Method performs regular operations onto the server.
bool HandleReceivedMessage(Server server, ClientData client, Message message)
Handles the received message.
Basic server class to handle TCP connections.
Definition: Server.cs:20
bool HandleClient(Server server, ClientData client)
Handles a new client.
bool HandleSendMessage(Server server, ClientData client, ref Message message)
Handles a message before sending.
Definition: Client.cs:14
EncryptionHandler(RSACryptoServiceProvider rsa)
Creates an instance of EncryptionHandler.