internal static IFreeformEntity_Msg InitKeyExchangeEndG2H_SIM(this FreeformSecurityTableCollection secTables,
                                                                      IFreeformEntity_Msg request)
        {
            // store the partial key of the host
            FFTgt_B2B_Security_KeyExchange_PartialKey tgt = request.EntityPrimaryTarget as FFTgt_B2B_Security_KeyExchange_PartialKey;
            SECURITY_KEY_INDEX keyIndex = FreeformEncryptionHelper.GetSecurityKeyIndex(request);

            byte[] gmuPartialKey = secTables.CreatePartialKeyGmu(keyIndex);
            secTables.StoreOtherPartialKeyGmu(keyIndex, tgt.PartialKey);
            secTables.CreateCommonKey(keyIndex);

            // send the partial key of the gmu
            IFreeformEntity_Msg response = request.CopyTo(FF_FlowDirection.G2H, new FFCreateEntityRequest_G2H_ResponseRequired()
            {
                MessageType       = FF_AppId_G2H_MessageTypes.FreeForm,
                Command           = FF_AppId_G2H_Commands.ResponseRequest,
                SkipTransactionId = true,
            });
            FFTgt_B2B_Security tgt2 = new FFTgt_B2B_Security()
            {
                SecurityData = new FFTgt_B2B_Security_KeyExchange_End()
                {
                    PartialKey = gmuPartialKey,
                }
            };

            response.AddTarget(tgt2);
            return(response);
        }
        internal static bool StoreOtherPartialKeyGmu(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key, byte[] partialKey)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "StoreOtherPartialKey"))
            {
                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(false);
                    }

                    FreeformSecurityTable secTable = secTables[key];
                    int length = FreeformSecurityTable.KEY_SIZE;
                    for (int i = 0, j = length - 1; i < length; i++, j = ((j + 3) & 0x7))
                    {
                        secTable.OtherPartialKey[j] = partialKey[i];
                    }

                    // indicates that other key is generated and common key is unusable
                    secTable.Flags = (secTable.Flags | FreeformSecurityFlags.OtherPartialKey) & ~FreeformSecurityFlags.CommonKey;
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(false);
                }

                return(true);
            }
        }
        internal static bool StoreOtherPartialKeyHost(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key, byte[] partialKey)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "StoreOtherPartialKey"))
            {
                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(false);
                    }

                    FreeformSecurityTable secTable = secTables[key];
                    int length = FreeformSecurityTable.KEY_SIZE_2;
                    for (int i = 0; i < length; ++i)
                    {
                        secTable.OtherPartialKey[i] = (byte)(partialKey[i] ^ ((byte)(0x50 + i)));
                    }

                    // method
                    secTable.Method = (((partialKey[length - 1] ^ 0xA5) >> 2) & 0x0F);

                    // indicates that other key is generated and common key is unusable
                    secTable.Flags = (secTable.Flags | FreeformSecurityFlags.OtherPartialKey) & ~FreeformSecurityFlags.CommonKey;
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(false);
                }

                return(true);
            }
        }
        internal static byte[] CreatePartialKeyHost(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "CreatePartialKey"))
            {
                byte[] result = null;

                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(result);
                    }

                    FreeformSecurityTable secTable = secTables[key];
                    byte[] keys = alphan;
                    int    j    = 0;

                    if (secTable.Method > (FK_1ST - 1))
                    {
                        secTable.Method = ((0xC3 * 100) % (FK_LST - FK_1ST + 1)) + FK_1ST;
                    }

                    if (secTable.Method == (int)FreeformSecurityMethodTypes.Alpha1)
                    {
                        keys = alpha1;
                    }
                    else if (secTable.Method == (int)FreeformSecurityMethodTypes.Alpha2)
                    {
                        keys = alpha2;
                    }
                    else
                    {
                        j = secTable.Method;
                    }

                    int i = 0;
                    for (int k = 3; i < 8; ++i, k = (k + 3) & 7)
                    {
                        secTable.LocalPartialKey[k] = exp_mod(keys[i + j], secTable.LocalRandomNumber[i]);
                    }
                    secTable.LocalPartialKey[8] = (byte)((0xC3 | (secTable.Method << 2)) ^ 0xA5);

                    // indicates that local partial key is generated and common key is unusable
                    secTable.Flags = (secTable.Flags | FreeformSecurityFlags.LocalPartialKey) & ~FreeformSecurityFlags.CommonKey;
                    result         = secTable.LocalPartialKey;
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(null);
                }

                return(result);
            }
        }
        internal static bool Decrypt(this FreeformSecurityTableCollection secTables, FF_FlowInitiation flowInitiation, SECURITY_KEY_INDEX key, ref byte[] data)
        {
            switch (flowInitiation)
            {
            case FF_FlowInitiation.Gmu:
                return(DecryptGmu(secTables, key, ref data));

            default:
                return(DecryptHost(secTables, key, ref data));
            }
        }
        internal static IFreeformEntity_Msg InitKeyExchangeStartG2H_SIM(this FreeformSecurityTableCollection secTables, string ipAddress, FF_AppId_SessionIds sessionId, int transactionId)
        {
            FreeformEntity_Msg message = FreeformEntityFactory.CreateEntity <FFMsg_G2H>(FF_FlowDirection.G2H,
                                                                                        new FFCreateEntityRequest_G2H_ResponseRequired()
            {
                Command       = FF_AppId_G2H_Commands.ResponseRequest,
                MessageType   = FF_AppId_G2H_MessageTypes.FreeForm,
                SessionID     = sessionId,
                TransactionID = transactionId,
                IPAddress     = ipAddress,
            });

            InitSecurityData(message, new FFTgt_B2B_Security_KeyExchange_Request());
            return(message);
        }
        internal static IFreeformEntity_Msg InitKeyExchangePartialKeyH2G_GMU(this FreeformSecurityTableCollection secTables,
                                                                             IFreeformEntity_Msg request)
        {
            SECURITY_KEY_INDEX keyIndex = FreeformEncryptionHelper.GetSecurityKeyIndex(request);

            byte[] hostPartialKey       = secTables.CreatePartialKeyHost(keyIndex);
            IFreeformEntity_Msg message = request.CopyTo(FF_FlowDirection.H2G, new FFCreateEntityRequest_H2G_ResponseRequired()
            {
                PollCode = FF_AppId_H2G_PollCodes.FreeformResponse,
            });

            InitSecurityData(message,
                             new FFTgt_B2B_Security_KeyExchange_PartialKey()
            {
                PartialKey = hostPartialKey,
            });
            return(message);
        }
        internal static bool DecryptHost(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key, ref byte[] data)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "Decrypt"))
            {
                if (data == null || data.Length == 0)
                {
                    return(false);
                }

                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(false);
                    }

                    FreeformSecurityTable secTable = secTables[key];
                    if ((secTable.Flags & FreeformSecurityFlags.CommonKey) != FreeformSecurityFlags.CommonKey)
                    {
                        return(false);
                    }

                    int j = 0;
                    if (secTable.Method == (int)FreeformSecurityMethodTypes.Alpha2)
                    {
                        j = 5;
                    }

                    for (int i = 0; i < data.Length; ++i)
                    {
                        data[i] ^= (byte)(secTable.CommonKey[(i + j) & 0x7] ^ fudge1[i & 0xF]);
                    }
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(false);
                }

                return(true);
            }
        }
        internal static bool CreateCommonKey(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "CreateCommonKey"))
            {
                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(false);
                    }

                    FreeformSecurityTable secTable = secTables[key];
                    if (secTable.Flags != (FreeformSecurityFlags.LocalPartialKey |
                                           FreeformSecurityFlags.OtherPartialKey))
                    {
                        return(false);
                    }

                    byte[] localNum = secTable.LocalRandomNumber;
                    for (int i = 0; i < FreeformSecurityTable.KEY_SIZE; i++)
                    {
                        secTable.CommonKey[i] = exp_mod(secTable.OtherPartialKey[i], localNum[i]);
                    }

                    // all the keys are now available
                    secTable.Flags |= (FreeformSecurityFlags.LocalPartialKey |
                                       FreeformSecurityFlags.OtherPartialKey |
                                       FreeformSecurityFlags.CommonKey);
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(false);
                }

                return(true);
            }
        }
        internal static byte GenerateRandomNumber(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "GenerateRandomNumber"))
            {
                byte result = 0;

                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(result);
                    }
                    result = secTables[key].GenerateRandomNumber();
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(0);
                }

                return(result);
            }
        }
        internal static IFreeformEntity_Msg InitKeyExchangeStatusH2G_GMU(this FreeformSecurityTableCollection secTables,
                                                                         IFreeformEntity_Msg request)
        {
            // store the partial key of the gmu
            FFTgt_B2B_Security_KeyExchange_End tgt = request.EntityPrimaryTarget as FFTgt_B2B_Security_KeyExchange_End;
            SECURITY_KEY_INDEX keyIndex            = FreeformEncryptionHelper.GetSecurityKeyIndex(request);

            secTables.StoreOtherPartialKeyHost(keyIndex, tgt.PartialKey);
            secTables.CreateCommonKey(keyIndex);

            IFreeformEntity_Msg message = request.CopyTo(FF_FlowDirection.H2G, new FFCreateEntityRequest_H2G_ResponseRequired()
            {
                PollCode = FF_AppId_H2G_PollCodes.FreeformNoResponse,
            });

            InitSecurityData(message,
                             new FFTgt_B2B_Security_KeyExchange_Status()
            {
                Status = (request.EntityPrimaryTarget is FFTgt_B2B_Security_PartialKey ?
                          FF_AppId_ResponseStatus_Types.Success :
                          FF_AppId_ResponseStatus_Types.Fail),
            });
            return(message);
        }
        internal static bool ClearKeyData(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "Decrypt"))
            {
                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(false);
                    }
                    FreeformSecurityTable secTable = secTables[key];

                    // clear the flags
                    secTable.Flags = 0;

                    // clear common key
                    for (int i = 0; i < secTable.CommonKey.Length; i++)
                    {
                        secTable.CommonKey[i] = 0;
                    }

                    // clear local key
                    for (int i = 0; i < secTable.LocalRandomNumber.Length; i++)
                    {
                        secTable.LocalRandomNumber[i] = 0;
                    }
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(false);
                }

                return(true);
            }
        }
        public byte[] Decrypt(IFreeformEntity_Msg message, byte[] buffer)
        {
            using (ILogMethod method = Log.LogMethod(this.DYN_MODULE_NAME, "Decrypt"))
            {
                List <byte> result = new List <byte>();

                try
                {
                    if (message == null ||
                        buffer == null ||
                        buffer.Length == 0)
                    {
                        return(new byte[0]);
                    }

                    FreeformSecurityTableCollection securityTables = FFMsgHandlerFactory.Current.GetSecurityTables(message.IpAddress);
                    SECURITY_KEY_INDEX securityKey    = message.GetSecurityKeyIndex();
                    ENCRYP_TARGETS     encryptionType = (ENCRYP_TARGETS)buffer[0];
                    FF_FlowInitiation  flowInitiation = message.FlowInitiation;
                    switch (encryptionType)
                    {
                    case ENCRYP_TARGETS.ET_SdsEncryption:
                    {
                        byte[] bufferCopy = buffer.CopyToBuffer(1, buffer.Length - 1);
                        FreeformEncryptionHelper.Decrypt(securityTables, flowInitiation, securityKey, ref bufferCopy);
                        result.AddRange(bufferCopy);
                    }
                    break;

                    case ENCRYP_TARGETS.ET_SdsAuthentication:
                    case ENCRYP_TARGETS.ET_EFTStyleEncryption:
                    {
                        byte   authenticationByteReceived = buffer[1];
                        byte[] bufferCopy = buffer.CopyToBuffer(2, buffer.Length - 2);
                        FreeformEncryptionHelper.Decrypt(securityTables, flowInitiation, securityKey, ref bufferCopy);

                        byte authenticationByteGenerated = FreeformEncryptionHelper.MakeAuthenticationByte(bufferCopy);
                        if (encryptionType == ENCRYP_TARGETS.ET_EFTStyleEncryption)
                        {
                            byte[] temp = new byte[] { authenticationByteGenerated };
                            FreeformEncryptionHelper.Decrypt(securityTables, flowInitiation, securityKey, ref temp);
                            authenticationByteGenerated = temp[0];
                        }
                        if (authenticationByteReceived == authenticationByteGenerated)
                        {
                            result.AddRange(bufferCopy);
                        }
                    }
                    break;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                }

                return(result.ToArray());
            }
        }
        public List <byte> Encrypt(IFreeformEntity_Msg message, IFreeformEntity_MsgTgt target, List <byte> buffer)
        {
            using (ILogMethod method = Log.LogMethod(this.DYN_MODULE_NAME, "Encrypt"))
            {
                List <byte> result = new List <byte>();

                try
                {
                    if (message == null ||
                        buffer == null ||
                        buffer.Count == 0)
                    {
                        return(result);
                    }

                    byte[] source = buffer.ToArray();
                    FreeformSecurityTableCollection securityTables = FFMsgHandlerFactory.Current.GetSecurityTables(message.IpAddress);
                    SECURITY_KEY_INDEX        securityKey          = message.GetSecurityKeyIndex();
                    FF_AppId_Encryption_Types encryptionType       = target.EncryptionType;
                    if (target.PrimaryTarget != null &&
                        target.PrimaryTarget.EncryptionType != FF_AppId_Encryption_Types.None)
                    {
                        encryptionType = target.PrimaryTarget.EncryptionType;
                    }

                    FF_FlowInitiation flowInitiation = message.FlowInitiation;
                    switch (encryptionType)
                    {
                    case FF_AppId_Encryption_Types.Standard:
                    {
                        FreeformEncryptionHelper.Encrypt(securityTables, flowInitiation, securityKey, ref source);
                        result.Add((byte)ENCRYP_TARGETS.ET_SdsEncryption);
                        result.AddRange(source);
                    }
                    break;

                    case FF_AppId_Encryption_Types.AuthByteClearData:
                    case FF_AppId_Encryption_Types.AuthByteEncryptedData:
                    {
                        byte[] authenticationByte = new byte[] { FreeformEncryptionHelper.MakeAuthenticationByte(source) };
                        if (encryptionType == FF_AppId_Encryption_Types.AuthByteEncryptedData)
                        {
                            result.Add((byte)ENCRYP_TARGETS.ET_EFTStyleEncryption);
                            FreeformEncryptionHelper.Encrypt(securityTables, flowInitiation, securityKey, ref authenticationByte);
                        }
                        else
                        {
                            result.Add((byte)ENCRYP_TARGETS.ET_SdsAuthentication);
                        }
                        FreeformEncryptionHelper.Encrypt(securityTables, flowInitiation, securityKey, ref source);
                        result.AddRange(authenticationByte);
                        result.AddRange(source);
                    }
                    break;

                    default:
                        result = buffer;
                        break;
                    }
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                }

                return(result);
            }
        }
        internal static byte[] CreatePartialKeyGmu(this FreeformSecurityTableCollection secTables, SECURITY_KEY_INDEX key)
        {
            using (ILogMethod method = Log.LogMethod(DYN_MODULE_NAME, "CreatePartialKey"))
            {
                byte[] result = null;

                try
                {
                    if (!secTables.ContainsKey(key))
                    {
                        return(result);
                    }

                    FreeformSecurityTable secTable = secTables[key];
                    byte[] keys = alphan;
                    int    j    = 0;

                    // initial method
                    if (secTable.Method == (int)FreeformSecurityMethodTypes.None)
                    {
                        secTable.Method = (int)FreeformSecurityMethodTypes.Alpha1;
                    }

                    if (secTable.Method == (int)FreeformSecurityMethodTypes.Alpha1)
                    {
                        keys = alpha1;
                    }
                    else if (secTable.Method == (int)FreeformSecurityMethodTypes.Alpha2)
                    {
                        keys = alpha2;
                    }
                    else
                    {
                        j = secTable.Method;
                    }

                    // 0 - 7
                    for (int i = 0; i < FreeformSecurityTable.KEY_SIZE; i++)
                    {
                        secTable.LocalPartialKey[i] = Convert.ToByte((exp_mod(keys[i + j], secTable.LocalRandomNumber[i]))
                                                                     ^ Convert.ToByte(0x50 + i));
                    }

                    // 8
                    j = FreeformSecurityTable.KEY_SIZE;
                    secTable.LocalPartialKey[j] = Convert.ToByte(((secTable.LocalRandomNumber[j] & 0xC3) |
                                                                  (secTable.Method << 2)) ^ 0xA5);

                    // indicates that local partial key is generated and common key is unusable
                    secTable.Flags = (secTable.Flags | FreeformSecurityFlags.LocalPartialKey) & ~FreeformSecurityFlags.CommonKey;
                    result         = secTable.LocalPartialKey;
                }
                catch (Exception ex)
                {
                    method.Exception(ex);
                    return(null);
                }

                return(result);
            }
        }