From 7ca14ee94204f2a39b8194037a059febbf557d97 Mon Sep 17 00:00:00 2001 From: Alex Macocian Date: Wed, 17 Jul 2019 16:01:43 +0300 Subject: [PATCH] Adding basic functionality and testing --- MTSC-TestServer/MTSC-TestServer.csproj | 13 ++ MTSC-TestServer/Program.cs | 14 +++ MTSC.sln | 8 +- MTSC/HelperFunctions.cs | 62 +++++++++ MTSC/Server/Handlers/EncryptionHandler.cs | 147 ++++++++++++++++++++++ MTSC/Server/Handlers/IHandler.cs | 2 +- MTSC/Server/Server.cs | 2 +- 7 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 MTSC-TestServer/MTSC-TestServer.csproj create mode 100644 MTSC-TestServer/Program.cs create mode 100644 MTSC/HelperFunctions.cs create mode 100644 MTSC/Server/Handlers/EncryptionHandler.cs diff --git a/MTSC-TestServer/MTSC-TestServer.csproj b/MTSC-TestServer/MTSC-TestServer.csproj new file mode 100644 index 0000000..fd5f0aa --- /dev/null +++ b/MTSC-TestServer/MTSC-TestServer.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp2.1 + MTSC_TestServer + + + + + + + diff --git a/MTSC-TestServer/Program.cs b/MTSC-TestServer/Program.cs new file mode 100644 index 0000000..f18dbde --- /dev/null +++ b/MTSC-TestServer/Program.cs @@ -0,0 +1,14 @@ +using MTSC.Server; +using System; + +namespace MTSC_TestServer +{ + class Program + { + static void Main(string[] args) + { + Server server = new Server(555); + server. + } + } +} diff --git a/MTSC.sln b/MTSC.sln index dff394d..3f20e1d 100644 --- a/MTSC.sln +++ b/MTSC.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29102.190 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTSC", "MTSC\MTSC.csproj", "{869DAEBC-5884-43C9-BA0B-2C4376A7ED1C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MTSC", "MTSC\MTSC.csproj", "{869DAEBC-5884-43C9-BA0B-2C4376A7ED1C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTSC-TestServer", "MTSC-TestServer\MTSC-TestServer.csproj", "{08A53F8F-BA6B-4C1C-B24B-CFD2626DE6C3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {869DAEBC-5884-43C9-BA0B-2C4376A7ED1C}.Debug|Any CPU.Build.0 = Debug|Any CPU {869DAEBC-5884-43C9-BA0B-2C4376A7ED1C}.Release|Any CPU.ActiveCfg = Release|Any CPU {869DAEBC-5884-43C9-BA0B-2C4376A7ED1C}.Release|Any CPU.Build.0 = Release|Any CPU + {08A53F8F-BA6B-4C1C-B24B-CFD2626DE6C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08A53F8F-BA6B-4C1C-B24B-CFD2626DE6C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08A53F8F-BA6B-4C1C-B24B-CFD2626DE6C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08A53F8F-BA6B-4C1C-B24B-CFD2626DE6C3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MTSC/HelperFunctions.cs b/MTSC/HelperFunctions.cs new file mode 100644 index 0000000..449dd8e --- /dev/null +++ b/MTSC/HelperFunctions.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace MTSC +{ + static class HelperFunctions + { + #region XML + + public static void FromXmlString(this RSA rsa, string xmlString) + { + RSAParameters parameters = new RSAParameters(); + + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlString); + + if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue")) + { + foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes) + { + switch (node.Name) + { + case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break; + } + } + } + else + { + throw new Exception("Invalid XML RSA key."); + } + + rsa.ImportParameters(parameters); + } + + public static string ToXmlString(this RSA rsa, bool includePrivateParameters) + { + RSAParameters parameters = rsa.ExportParameters(includePrivateParameters); + + return string.Format("{0}{1}

{2}

{3}{4}{5}{6}{7}
", + parameters.Modulus != null ? Convert.ToBase64String(parameters.Modulus) : null, + parameters.Exponent != null ? Convert.ToBase64String(parameters.Exponent) : null, + parameters.P != null ? Convert.ToBase64String(parameters.P) : null, + parameters.Q != null ? Convert.ToBase64String(parameters.Q) : null, + parameters.DP != null ? Convert.ToBase64String(parameters.DP) : null, + parameters.DQ != null ? Convert.ToBase64String(parameters.DQ) : null, + parameters.InverseQ != null ? Convert.ToBase64String(parameters.InverseQ) : null, + parameters.D != null ? Convert.ToBase64String(parameters.D) : null); + } + + #endregion + } +} diff --git a/MTSC/Server/Handlers/EncryptionHandler.cs b/MTSC/Server/Handlers/EncryptionHandler.cs new file mode 100644 index 0000000..aad1f8f --- /dev/null +++ b/MTSC/Server/Handlers/EncryptionHandler.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using MTSC; + +namespace MTSC.Server.Handlers +{ + /// + /// Handler that encrypts the communication. + /// + public class EncryptionHandler : IHandler + { + private enum ClientState + { + Initial, + Negotiating, + Encrypted + } + private struct AdditionalData + { + public byte[] Key; + public ClientState ClientState; + } + private Dictionary additionalData; + private RSA rsa; + private string privateKey, publicKey; + /// + /// Creates an instance of EncryptionHandler. + /// + /// Symmetrical algorithm to be used for end-to-end encryption. + public EncryptionHandler(RSA rsa) + { + additionalData = new Dictionary(); + privateKey = rsa.ToXmlString(true); + publicKey = rsa.ToXmlString(false); + } + + public void ClientRemoved(ClientStruct client) + { + throw new NotImplementedException(); + } + + public bool HandleClient(ClientStruct client) + { + throw new NotImplementedException(); + } + + public bool HandleMessage(ClientStruct client, Message message) + { + throw new NotImplementedException(); + } + + public bool PreHandleMessage(ClientStruct client, ref Message message) + { + if(additionalData[client].ClientState == ClientState.Encrypted) + { + /* + * Decrypt message before returning. + */ + byte[] encryptedBytes = message.MessageBytes; + byte[] decryptedBytes = DecryptBytes(additionalData[client].Key, encryptedBytes); + message = new Message((uint)decryptedBytes.Length, decryptedBytes); + return false; + } + else + { + /* + * If the state of the client is not encrypted, there's nothing to decrypt. + */ + return false; + } + } + + + private byte[] EncryptBytes(byte[] clientKey, byte[] bytesToBeEncrypted) + { + byte[] encryptedBytes = null; + + // Set your salt here, change it to meet your flavor: + // The salt bytes must be at least 8 bytes. + byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + + using (MemoryStream ms = new MemoryStream()) + { + using (RijndaelManaged AES = new RijndaelManaged()) + { + AES.KeySize = 256; + AES.BlockSize = 128; + + AES.Mode = CipherMode.CBC; + + var key = new Rfc2898DeriveBytes(clientKey, saltBytes, 1000); + AES.Key = key.GetBytes(AES.KeySize / 8); + AES.IV = key.GetBytes(AES.BlockSize / 8); + + + + using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write)) + { + cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length); + cs.Close(); + } + encryptedBytes = ms.ToArray(); + } + } + + return encryptedBytes; + } + + private byte[] DecryptBytes(byte[] clientKey, byte[] bytesToBeDecrypted) + { + byte[] decryptedBytes = null; + + // Set your salt here, change it to meet your flavor: + // The salt bytes must be at least 8 bytes. + byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + + using (MemoryStream ms = new MemoryStream()) + { + using (RijndaelManaged AES = new RijndaelManaged()) + { + AES.KeySize = 256; + AES.BlockSize = 128; + + AES.Mode = CipherMode.CBC; + + var key = new Rfc2898DeriveBytes(clientKey, saltBytes, 1000); + AES.Key = key.GetBytes(AES.KeySize / 8); + AES.IV = key.GetBytes(AES.BlockSize / 8); + + + + using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write)) + { + cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length); + cs.Close(); + } + decryptedBytes = ms.ToArray(); + } + } + + return decryptedBytes; + } + } +} diff --git a/MTSC/Server/Handlers/IHandler.cs b/MTSC/Server/Handlers/IHandler.cs index cc7b950..2196c51 100644 --- a/MTSC/Server/Handlers/IHandler.cs +++ b/MTSC/Server/Handlers/IHandler.cs @@ -23,7 +23,7 @@ namespace MTSC.Server.Handlers /// Client structure. /// Message to be preprocessed. /// True if the message has been preprocessed and no other handler should handle it anymore. - bool PreHandleMessage(ClientStruct client, out Message message); + bool PreHandleMessage(ClientStruct client, ref Message message); /// /// Handles the received message. /// diff --git a/MTSC/Server/Server.cs b/MTSC/Server/Server.cs index e5b85f9..189efd2 100644 --- a/MTSC/Server/Server.cs +++ b/MTSC/Server/Server.cs @@ -134,7 +134,7 @@ namespace MTSC.Server } foreach (IHandler handler in handlers) { - if (handler.PreHandleMessage(client, out message)) + if (handler.PreHandleMessage(client, ref message)) { break; }