/// <summary>
        /// Encodes a key-exchange-instruction
        /// from client to server.
        /// </summary>
        /// <returns>The encoded string</returns>
        private string EncodeKeyExchangeC2S()
        {
            StringBuilder innersb = new StringBuilder();
            StringBuilder sb      = new StringBuilder();

            innersb.Append($"IID:{ID}$");
            innersb.Append($"FWV:{FrameworkVersion}$");
            innersb.Append($"ISV:{InstructionSetVersion}$");
            innersb.Append($"PUK:{Sender?.RSAKeys.PublicKey}$");
            innersb.Append($"USR:{Base64Handler.Encode(Sender?.Username)}$");
            innersb.Append($"INS:{instruction}$");

            sb.Append(innersb.ToString());
            sb.Append("%");

            return(sb.ToString());
        }
        /// <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());
        }
Beispiel #3
0
        /// <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());
        }