2 using System.Collections.Generic;
4 using System.Net.Sockets;
5 using System.Security.Cryptography;
13 private enum ConnectionState
21 private ConnectionState connectionState = ConnectionState.Initial;
22 private byte[] aesKey;
34 #region Public Methods 37 #region Private Methods 38 private string GetUniqueKey(
int size)
40 return Convert.ToBase64String(GetUniqueByteKey(size));
43 private byte[] GetUniqueByteKey(
int size)
45 byte[] data =
new byte[size];
46 using (RNGCryptoServiceProvider crypto =
new RNGCryptoServiceProvider())
48 crypto.GetBytes(data);
53 private byte[] EncryptBytes(
byte[] bytesToBeEncrypted)
55 byte[] encryptedBytes =
null;
59 byte[] saltBytes =
new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
61 using (MemoryStream ms =
new MemoryStream())
63 using (RijndaelManaged AES =
new RijndaelManaged())
67 AES.Mode = CipherMode.CBC;
68 var key =
new Rfc2898DeriveBytes(aesKey, saltBytes, 1000);
69 AES.Key = key.GetBytes(AES.KeySize / 8);
70 AES.IV = key.GetBytes(AES.BlockSize / 8);
72 using (var cs =
new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
74 cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
77 encryptedBytes = ms.ToArray();
81 return encryptedBytes;
84 private byte[] DecryptBytes(
byte[] bytesToBeDecrypted)
86 byte[] decryptedBytes =
null;
90 byte[] saltBytes =
new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
92 using (MemoryStream ms =
new MemoryStream())
94 using (RijndaelManaged AES =
new RijndaelManaged())
99 AES.Mode = CipherMode.CBC;
101 var key =
new Rfc2898DeriveBytes(aesKey, saltBytes, 1000);
102 AES.Key = key.GetBytes(AES.KeySize / 8);
103 AES.IV = key.GetBytes(AES.BlockSize / 8);
107 using (var cs =
new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
109 cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
112 decryptedBytes = ms.ToArray();
116 return decryptedBytes;
119 private string EncryptText(
string input)
122 byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
124 byte[] bytesEncrypted = EncryptBytes(bytesToBeEncrypted);
126 string result = Encoding.UTF8.GetString(bytesEncrypted);
131 private string DecryptText(
string input)
134 byte[] bytesToBeDecrypted = Encoding.UTF8.GetBytes(input);
136 byte[] bytesDecrypted = DecryptBytes(bytesToBeDecrypted);
138 string result = Encoding.UTF8.GetString(bytesDecrypted);
143 #region Interface Implementation 151 this.connectionState = ConnectionState.Initial;
170 if (connectionState == ConnectionState.Encrypted)
172 byte[] decryptedBytes = message.MessageBytes;
173 byte[] encryptedBytes = EncryptBytes(decryptedBytes);
174 message = CommunicationPrimitives.BuildMessage(encryptedBytes);
187 if (connectionState == ConnectionState.Encrypted)
189 byte[] encryptedBytes = message.MessageBytes;
190 byte[] decryptedBytes = DecryptBytes(encryptedBytes);
191 message = CommunicationPrimitives.BuildMessage(decryptedBytes);
204 if (connectionState == ConnectionState.RequestingPublicKey)
206 string ascii = ASCIIEncoding.ASCII.GetString(message.MessageBytes);
207 if (ascii.Contains(CommunicationPrimitives.SendPublicKey))
209 byte[] publicKeyBytes =
new byte[message.MessageLength - CommunicationPrimitives.SendPublicKey.Length - 1];
210 Array.Copy(message.MessageBytes, CommunicationPrimitives.SendPublicKey.Length + 1, publicKeyBytes, 0, publicKeyBytes.Length);
211 string publicKey = ASCIIEncoding.ASCII.GetString(publicKeyBytes);
212 RSACryptoServiceProvider rsa =
new RSACryptoServiceProvider(1024);
213 RSAParameters parameters =
new RSAParameters();
214 XmlDocument xmlDoc =
new XmlDocument();
215 xmlDoc.LoadXml(publicKey);
216 if (xmlDoc.DocumentElement.Name.Equals(
"RSAKeyValue"))
218 foreach (XmlNode node
in xmlDoc.DocumentElement.ChildNodes)
222 case "Modulus": parameters.Modulus = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
223 case "Exponent": parameters.Exponent = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
224 case "P": parameters.P = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
225 case "Q": parameters.Q = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
226 case "DP": parameters.DP = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
227 case "DQ": parameters.DQ = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
228 case "InverseQ": parameters.InverseQ = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
229 case "D": parameters.D = (
string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText));
break;
233 rsa.ImportParameters(parameters);
234 byte[] symkeyBytes = GetUniqueByteKey(32);
235 byte[] encryptedSymKey = rsa.Encrypt(symkeyBytes,
false);
236 aesKey = symkeyBytes;
237 byte[] messageHeader = ASCIIEncoding.ASCII.GetBytes(CommunicationPrimitives.SendEncryptionKey +
":");
238 byte[] messageBytes =
new byte[encryptedSymKey.Length + messageHeader.Length];
239 Array.Copy(messageHeader, 0, messageBytes, 0, messageHeader.Length);
240 Array.Copy(encryptedSymKey, 0, messageBytes, messageHeader.Length, encryptedSymKey.Length);
242 connectionState = ConnectionState.NegotiatingSymKey;
246 else if (connectionState == ConnectionState.NegotiatingSymKey)
248 string ascii = ASCIIEncoding.ASCII.GetString(DecryptBytes(message.MessageBytes));
249 if (ascii == CommunicationPrimitives.AcceptEncryptionKey)
251 connectionState = ConnectionState.Encrypted;
256 connectionState = ConnectionState.Initial;
269 if (connectionState == ConnectionState.Initial)
272 client.
QueueMessage(ASCIIEncoding.ASCII.GetBytes(CommunicationPrimitives.RequestPublicKey));
273 this.connectionState = ConnectionState.RequestingPublicKey;
EncryptionHandler()
Creates an instance of EncryptionHandler.
bool HandleSendMessage(Client client, ref Message message)
Called when a message is being sent to the server.
bool PreHandleReceivedMessage(Client client, ref Message message)
Called before the message is handled. Use this method to modify the message if necesarry.
bool HandleReceivedMessage(Client client, Message message)
Called when a message has been received.
void Tick(Client client)
Called every cycle. This method should perform regular actions on the connection.
bool InitializeConnection(Client client)
Called when the connection is being initialized.
void Disconnected(Client client)
Called when the client is disconnected.
void QueueMessage(byte[] message)
Add a message to the message queue.
Handler interface for client communication.
Base class for TCP Client.