/// <summary>
        /// Обрабатывает команду перехода в шифрованный чат
        /// </summary>
        unsafe void HandleCryptCommand(TcpPortHandler handler, TcpClientNode node, string[] values)
        {
            _chatEncoded    = true;
            _gameGSkeyBytes = null;

            // В зависимости от игры. Байты шифрования отличаются. Таблица есть в инете
            // https://gamerecon.net/support/topic/gamespy-supported-games-list/
            // https://github.com/luisj135/nintendo_dwc_emulator/blob/master/gslist.cfg

            // Dawn of War
            if (values.Contains("dow"))
            {
                _gameGSkey       = "dow";
                _gameGSNameBytes = "dow".ToAsciiBytes();
                _gameGSkeyBytes  = "VLxgwe".ToAsciiBytes();
            }

            // Dawn of War (более похоже на правду)
            if (values.Contains("whammer40000"))
            {
                _gameGSkey       = "whammer40000";
                _gameGSNameBytes = "whammer40000".ToAsciiBytes();
                _gameGSkeyBytes  = "uJ8d3N".ToAsciiBytes();
            }

            // Winter Assault
            // ключа почему-то нет в таблице. Возьмем ключ 1 дова.
            // TODO: Надо потестить WA
            if (values.Contains("dowwad"))
            {
                _gameGSkey       = "dowwad";
                _gameGSNameBytes = "dowwad".ToAsciiBytes();
                _gameGSkeyBytes  = "uJ8d3N".ToAsciiBytes();
            }

            // Dark Crusade
            if (values.Contains("whammer40kdc"))
            {
                _gameGSkey       = "whammer40kdc";
                _gameGSNameBytes = "whammer40kdc".ToAsciiBytes();
                _gameGSkeyBytes  = "Ue9v3H".ToAsciiBytes();
            }

            // Soulstorm
            if (values.Contains("whamdowfr"))
            {
                _gameGSkey       = "whamdowfr";
                _gameGSNameBytes = "whamdowfr".ToAsciiBytes();
                _gameGSkeyBytes  = "pXL838".ToAsciiBytes();
            }

            if (_gameGSkeyBytes == null)
            {
                Restart();
                return;
            }

            // Ключ шифрования. Для простоты просто нули. Не тестил, что будет, если не нули.
            var chall = "0000000000000000".ToAsciiBytes();

            var clientKey = new ChatCrypt.GDCryptKey();
            var serverKey = new ChatCrypt.GDCryptKey();

            // Инициализируем структуры-ключи для выполнения алгоритма спая
            fixed(byte *challPtr = chall)
            {
                fixed(byte *gamekeyPtr = _gameGSkeyBytes)
                {
                    ChatCrypt.GSCryptKeyInit(clientKey, challPtr, gamekeyPtr, _gameGSkeyBytes.Length);
                    ChatCrypt.GSCryptKeyInit(serverKey, challPtr, gamekeyPtr, _gameGSkeyBytes.Length);
                }
            }

            // Сохраняем структуры
            _chatClientKey = clientKey;
            _chatServerKey = serverKey;

            // Отправляем идентичные ключи для сервера и клиента. Шифрование в итоге будет полностью совпадать.
            // С этого момента чат шифрованный
            handler.SendAskii(node, ":s 705 * 0000000000000000 0000000000000000\r\n");
        }
Beispiel #2
0
 /// <summary>
 /// Обрабатывает входящие TCP соединения для сервера LOGIN (Client)
 /// </summary>
 void OnClientAccept(TcpPortHandler handler, TcpClientNode node, CancellationToken token)
 {
     //Обновляем челендж для нового соединения
     _serverChallenge = RandomHelper.GetString(10);
     handler.SendAskii(node, $@"\lc\1\challenge\{_serverChallenge}\id\1\final\");
 }
Beispiel #3
0
        /// <summary>
        /// Обрабатывает одно сообщение сервера
        /// </summary>
        private void HandleClientManagerMessage(TcpPortHandler handler, TcpClientNode node, string mes)
        {
            LogTrace("CLIENT " + mes);
            var pairs = ParseHelper.ParseMessage(mes, out string query);

            if (pairs == null || string.IsNullOrWhiteSpace(query))
            {
                return;
            }

            // Исправление бага, когда игра по какой-то причине соединяет логин и почту в одну строку. Разбиваем, иначе не будет работать алгоритм хэширования при логине
            if (pairs.ContainsKey("name") && !pairs.ContainsKey("email"))
            {
                var parts = pairs["name"].Split('@');

                if (parts.Length > 2)
                {
                    pairs["name"]  = parts[0];
                    pairs["email"] = parts[1] + "@" + parts[2];
                }
            }

            switch (query)
            {
            case "login":
                HandleLogin(node, pairs);
                RestartUserSessionTimer(node);
                break;

            case "logout":
                _emulationAdapter.LeaveFromCurrentLobby();
                _emulationAdapter.OnLogout();
                break;

            case "registernick":
                handler.SendAskii(node, string.Format(@"\rn\{0}\id\{1}\final\", pairs["uniquenick"], pairs["id"]));
                break;

            case "ka":
                handler.SendAskii(node, $@"\ka\\final\");
                break;

            case "status":
                HandleStatus(node, pairs);
                break;

            case "newuser":
            {
                var nick     = pairs["nick"];
                var email    = pairs["email"];
                var password = GSUtils.DecryptPassword(pairs["passwordenc"]);
                var passHash = password.ToMD5();

                _emulationAdapter.TryCreateProfile(nick, email, passHash);
            }
            break;

            case "getprofile":
                // TODO
                break;

            default:
                Debugger.Break();
                break;
            }
        }
Beispiel #4
0
        void OnSearchManagerReceived(TcpPortHandler handler, TcpClientNode node, byte[] buffer, int count)
        {
            var str   = buffer.ToUtf8(count);
            var pairs = ParseHelper.ParseMessage(str, out string query);


            switch (query)
            {
            case "nicks":
            {
                // \\nicks\\\\email\\[email protected]\\passenc\\J4PGhRi[\\namespaceid\\7\\partnerid\\0\\gamename\\whamdowfr\\final\\

                if (!pairs.ContainsKey("email") || (!pairs.ContainsKey("passenc") && !pairs.ContainsKey("pass")))
                {
                    handler.SendAskii(node, @"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                    return;
                }

                // Чей-то тестовый код

                /*
                 * string password = String.Empty;
                 * if (pairs.ContainsKey("passenc"))
                 * {
                 *  password = GSUtils.DecryptPassword(pairs["passenc"]);
                 * }
                 * else if (pairs.ContainsKey("pass"))
                 * {
                 *  password = pairs["pass"];
                 * }
                 *
                 * password = password.ToMD5();*/

                _emulationAdapter.RequestAllUserNicks(pairs["email"]);
                return;
            }

            case "check":
            {
                string name = String.Empty;

                if (String.IsNullOrWhiteSpace(name))
                {
                    if (pairs.ContainsKey("uniquenick"))
                    {
                        name = pairs["uniquenick"];
                    }
                }
                if (String.IsNullOrWhiteSpace(name))
                {
                    if (pairs.ContainsKey("nick"))
                    {
                        name = pairs["nick"];
                    }
                }

                if (String.IsNullOrWhiteSpace(name))
                {
                    handler.SendAskii(node, @"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                    return;
                }

                _emulationAdapter.RequestNameCheck(name);
                return;
            }

            default:
                break;
            }

            Debugger.Break();
        }