/// <summary> /// Creates a new instance of the NetCom-Server on a given port. /// </summary> /// <param name="pPort">Target TCP-Port</param> public NetComServer(int pPort) { port = pPort; serverIP = IPAddress.Any; RSAKeys = RSAHandler.GenerateKeyPair(); }
/// <summary> /// Creates a new NetCom-client instance. /// </summary> /// <param name="pServerIP">IP of the server</param> /// <param name="pPort">TCP port of the server</param> public NetComClient(IPAddress pServerIP, int pPort) { RSAKeys = RSAHandler.GenerateKeyPair(); port = pPort; serverIP = pServerIP; }
/// <summary> /// Encodes the message and returns it as a string. /// </summary> /// <returns>The encoded string</returns> public string Encode() { if (this.GetType() == typeof(InstructionLibraryEssentials.KeyExchangeServer2Client)) { return(EncodeKeyExchangeS2C()); } if (this.GetType() == typeof(InstructionLibraryEssentials.KeyExchangeClient2Server)) { return(EncodeKeyExchangeC2S()); } bool rsaEncryption = false; if (Receiver.RSAKeys.PublicKey != null) { rsaEncryption = true; } StringBuilder innersb = new StringBuilder(); StringBuilder sb = new StringBuilder(); if (rsaEncryption) { sb.Append("R:"); } // Instruction-ID innersb.Append($"IID:{ID}$"); // Version Data (Framework and instructionset) innersb.Append($"FWV:{FrameworkVersion}$"); innersb.Append($"ISV:{InstructionSetVersion}$"); // User Data if (Sender?.RSAKeys.PublicKey != null) { innersb.Append($"PUK:{Sender?.RSAKeys.PublicKey}$"); } if (Sender?.Username != null) { innersb.Append($"USR:{Base64Handler.Encode(Sender?.Username)}$"); } if (Sender?.Password != null) { if (rsaEncryption) { innersb.Append($"PSW:{RSAHandler.Encrypt(Receiver?.RSAKeys.PublicKey, Sender?.Password)}$"); } else { innersb.Append($"PSW:{Base64Handler.Encode(Sender?.Password)}$"); } } // Signature if (Sender?.RSAKeys.PrivateKey != null) { Guid signature = Guid.NewGuid(); innersb.Append($"SGP:{signature.ToString()}$"); innersb.Append($"SGC:{RSAHandler.Sign(Sender?.RSAKeys.PrivateKey, signature.ToString())}$"); } // Actuall data if (instruction != null) { innersb.Append($"INS:{instruction}$"); } if (value != null) { innersb.Append($"VAL:{Base64Handler.Encode(value)}$"); } if (parameters != null) { innersb.Append($"PAR:"); foreach (object param in parameters) { innersb.Append($"{param.GetType().AssemblyQualifiedName}#{Base64Handler.Encode(param.ToString())}|"); } innersb.Append($"$"); } sb.Append(innersb.ToString()); sb.Append("%"); return(sb.ToString()); }
/// <summary> /// Parses an encoded instruction-string and returns /// all instruction-objects included in the string. /// </summary> /// <param name="pLocalUser">Local user</param> /// <param name="pReceptionSocket">Remote user, from which the instruction was received</param> /// <param name="pInstructionString">Encoded instruction-string. Can contain multiple instructions.</param> /// <param name="pServerClientList">Client-List for authentication (NetComServer only!)</param> /// <returns></returns> internal static IEnumerable <InstructionBase> Parse(NetComUser pLocalUser, Socket pReceptionSocket, string pInstructionString, ClientList pServerClientList = null) { // RSA:<Base64>;RSA:<Base64>; List <InstructionBase> retInstr = new List <InstructionBase>(); lock (pLocalUser) { foreach (string encodedInstruction in pInstructionString.Split('%')) { if (string.IsNullOrEmpty(encodedInstruction)) { continue; } string instructionID = null; string frameworkVersion = null; string instructionsetVersion = null; string username = null; string password = null; string instruction = null; string value = null; List <object> parameters = new List <object>(); string signaturePlain = null; string signatureRSA = null; string publicKey = null; NetComUser user = null; // RSA:<Base64> bool rsaEncoded = false; string encInstr = encodedInstruction; if (encInstr.StartsWith("R:")) { rsaEncoded = true; encInstr = encInstr.Remove(0, 2); } // <Base64> string decodedInstruction; try { //decodedInstruction = Base64Handler.Decode(encInstr); decodedInstruction = encInstr; } catch (Exception ex) { (pLocalUser as NetComOperator).Debug("Instruction-Parsing: Could not decode from Base64.", DebugType.Error); if ((pLocalUser as NetComOperator).ShowExceptions) { (pLocalUser as NetComOperator).Debug($"({ex.GetType().Name}) {ex.Message}", DebugType.Exception); } continue; } // INS:B64,VAL:B64,PAR:B64#B64|B64#B64|, foreach (string encodedInstrSegment in decodedInstruction.Split('$')) { if (string.IsNullOrEmpty(encodedInstrSegment)) { continue; } // INS:B64 / PAR:B64#B64|B64#B64| string[] encodedSegmentParts = encodedInstrSegment.Split(':'); switch (encodedSegmentParts[0]) { case "IID": instructionID = encodedSegmentParts[1]; break; case "FWV": frameworkVersion = encodedSegmentParts[1]; break; case "ISV": instructionsetVersion = encodedSegmentParts[1]; break; case "PUK": publicKey = encodedSegmentParts[1]; break; case "USR": username = Base64Handler.Decode(encodedSegmentParts[1], "ERROR"); break; case "PSW": if (rsaEncoded) { password = RSAHandler.Decrypt(pLocalUser.RSAKeys.PrivateKey, encodedSegmentParts[1]); } break; case "SGP": signaturePlain = encodedSegmentParts[1]; break; case "SGC": if (rsaEncoded) { signatureRSA = encodedSegmentParts[1]; } break; case "INS": instruction = encodedSegmentParts[1]; break; case "VAL": value = Base64Handler.Decode(encodedSegmentParts[1], "ERROR"); break; case "PAR": foreach (string paramGroup in encodedSegmentParts[1].Split('|')) { if (string.IsNullOrEmpty(paramGroup)) { continue; } string[] paramParts = paramGroup.Split('#'); string paramTypeStr = paramParts[0]; string paramValueStr = Base64Handler.Decode(paramParts[1], "ERROR"); Type paramType = Type.GetType(paramTypeStr); try { object convParam = null; TypeConverter converter = TypeDescriptor.GetConverter(paramType); if (converter != null) { convParam = converter.ConvertFromString(paramValueStr); } else { convParam = null; } parameters.Add(convParam); } catch (NotSupportedException ex) { (pLocalUser as NetComOperator).Debug("Broadcast-Error.", DebugType.Error); if ((pLocalUser as NetComOperator).ShowExceptions) { (pLocalUser as NetComOperator).Debug($"({ex.GetType().Name}) {ex.Message}", DebugType.Exception); } throw new NetComParsingException($"*** Could not parse the following parameter: Type: {paramTypeStr}, Value: {paramValueStr} ***"); } } break; } } // Check if the instruction has been processed before if (instruction != typeof(InstructionLibraryEssentials.ReceptionConfirmation).AssemblyQualifiedName) { if ((pLocalUser as NetComOperator).InstructionLogIncomming.Contains(instructionID)) { if (pLocalUser.GetType() == typeof(NetComClient)) { (pLocalUser as NetComClient).Send(new InstructionLibraryEssentials.ReceptionConfirmation(pLocalUser, null, instructionID)); } if (pLocalUser.GetType() == typeof(NetComServer)) { (pLocalUser as NetComServer).Send(new InstructionLibraryEssentials.ReceptionConfirmation(pLocalUser, (pLocalUser as NetComServer).ConnectedClients[pReceptionSocket], instructionID)); } continue; } } // Check instructionset-version if (ForceInstructionsetVersion && InstructionBase.InstructionSetVersion != instructionsetVersion) { throw new NetComVersionException($"*** The received package uses a different verion of the Instruction-Set! Local version: {InstructionBase.InstructionSetVersion} - Senders version: {instructionsetVersion} ***"); } // Check framework-version if (ForceFrameworkVersion && InstructionBase.FrameworkVersion != frameworkVersion) { throw new NetComVersionException($"*** The received package was built using a different verion of the Framework! Local version: {InstructionBase.FrameworkVersion} - Senders version: {frameworkVersion} ***"); } // Check signature if (rsaEncoded && !RSAHandler.Verify(publicKey, signaturePlain, signatureRSA)) { throw new NetComSignatureException("*** The received packets signature is invalid! ***"); } if (pServerClientList != null) { // Server -> Assign received data to clientlist pServerClientList[pReceptionSocket].SetUserData(username, password, publicKey); if (instruction != typeof(InstructionLibraryEssentials.KeyExchangeClient2Server).AssemblyQualifiedName && instruction != typeof(InstructionLibraryEssentials.ReceptionConfirmation).AssemblyQualifiedName && !pServerClientList[pReceptionSocket].Authenticate(password)) { throw new NetComAuthenticationException("*** Authentication failed! Wrong username / password ***"); } user = pServerClientList[pReceptionSocket]; } else { // Client -> Ignore authentication-data user = new NetComUser(); user.SetUserData(username, password, publicKey); } try { if (instruction == typeof(InstructionLibraryEssentials.ReceptionConfirmation).AssemblyQualifiedName) { retInstr.Add((InstructionBase)Activator.CreateInstance(Type.GetType(instruction), user, pLocalUser, value)); } else if (value == null && parameters.Count == 0) { retInstr.Add((InstructionBase)Activator.CreateInstance(Type.GetType(instruction), user, pLocalUser)); } else if (parameters.Count == 0) { retInstr.Add((InstructionBase)Activator.CreateInstance(Type.GetType(instruction), user, pLocalUser, value)); } else { retInstr.Add((InstructionBase)Activator.CreateInstance(Type.GetType(instruction), user, pLocalUser, value, parameters.ToArray())); } // Increment the total receive counter (pLocalUser as NetComOperator).TotalReceiveCounter++; // Send confirmation (if the instruction is not a confirmation itself) if (instruction != typeof(InstructionLibraryEssentials.ReceptionConfirmation).AssemblyQualifiedName) { (pLocalUser as NetComOperator).InstructionLogIncomming.Add(instructionID); if (pLocalUser.GetType() == typeof(NetComClient)) { (pLocalUser as NetComClient).Send(new InstructionLibraryEssentials.ReceptionConfirmation(pLocalUser, null, instructionID)); } if (pLocalUser.GetType() == typeof(NetComServer)) { (pLocalUser as NetComServer).Send(new InstructionLibraryEssentials.ReceptionConfirmation(pLocalUser, (pLocalUser as NetComServer).ConnectedClients[pReceptionSocket], instructionID)); } } } catch (Exception ex) { (pLocalUser as NetComOperator).Debug("Could not recreate the instruction.", DebugType.Error); if ((pLocalUser as NetComOperator).ShowExceptions) { (pLocalUser as NetComOperator).Debug($"({ex.GetType().Name}) {ex.Message}", DebugType.Exception); } } } } return(retInstr.ToArray()); }