コード例 #1
0
ファイル: MiNetAuth.cs プロジェクト: xpyctum/MiNetAuth
 public Package PlayerJoin(McpeLogin package, Player player)
 {
     if (!_notdefaultlevel)
     {
         player.Level.BlockBreak += OnBreak;
         player.Level.BlockPlace += OnPlace;
         _notdefaultlevel = true;
     }
     if (!(_registerlist.Contains(player.User)))
     {
         player.AddPopup(new Popup()
         {
             Message = "Используй /reg [пароль] для регистрации",
             MessageType = MessageType.Popup
         });
     }
     else
     {
         player.User = _registerlist.Find(t => t.UserName == player.Username);
         if (!player.User.IsAuthenticated)
             player.AddPopup(new Popup()
             {
                 Message = "Используй /auth [пароль] чтобы войти",
                 MessageType = MessageType.Popup
             });
     }
     return package;
 }
コード例 #2
0
        public virtual void HandleMcpeLogin(McpeLogin message)
        {
            // Only one login!
            lock (_loginSyncLock)
            {
                if (_session.Username != null)
                {
                    Log.Info($"Player {_session.Username} doing multiple logins");
                    return;                     // Already doing login
                }

                _session.Username = string.Empty;
            }

            _playerInfo.ProtocolVersion = message.protocolVersion;

            if (MiNetServer.IsRunningOnMono())
            {
                DecodeCertMono(message);
            }
            else
            {
                DecodeCert(message);
            }
        }
コード例 #3
0
ファイル: MinetServerTest.cs プロジェクト: venomshock/MiNET
        public void TestUuid()
        {
            var  rfc4122Bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
            UUID uuid         = new UUID(rfc4122Bytes);

            Assert.AreEqual(rfc4122Bytes, uuid.GetBytes());

            Skin skin = new Skin {
                Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))
            };
            var packet = McpeLogin.CreateObject();

            packet.username      = "******";
            packet.protocol      = 34;
            packet.protocol2     = 34;
            packet.clientId      = new Random().Next();
            packet.clientUuid    = new UUID(Guid.NewGuid().ToByteArray());
            packet.serverAddress = "83.249.65.92:19132";
            packet.clientSecret  = "iwmvi45hm85oncyo58";
            packet.skin          = skin;

            var bytes = packet.Encode();

            Console.WriteLine(Package.HexDump(bytes, 16));

            UUID uuid2 = new UUID(rfc4122Bytes);

            Dictionary <UUID, string> uuiDictionary = new Dictionary <UUID, string>();

            uuiDictionary.Add(uuid, "test");

            Assert.AreEqual("test", uuiDictionary[uuid2]);
        }
コード例 #4
0
ファイル: MiNetClient.cs プロジェクト: TheDiamondYT2/MiNET
        public void SendLogin(string username)
        {
            Skin skin = new Skin {
                Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))
            };

            skin.SkinType = "Standard_Custom";
            //Skin skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 16384)) };
            var packet = new McpeLogin()
            {
                username      = username,
                protocol      = 38,
                protocol2     = 38,
                clientId      = ClientId,
                clientUuid    = new UUID(Guid.NewGuid().ToByteArray()),
                serverAddress = _serverEndpoint.Address + ":" + _serverEndpoint.Port,
                clientSecret  = "iwmvi45hm85oncyo58",
                //clientSecret = Encoding.ASCII.GetString(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("" + ClientId + _serverEndpoint.Address + _serverEndpoint.Port))),
                skin = skin,
            };

            byte[] buffer = Player.CompressBytes(packet.Encode(), CompressionLevel.Fastest, true);

            McpeBatch batch = new McpeBatch();

            batch.payloadSize = buffer.Length;
            batch.payload     = buffer;
            batch.Encode();

            SendPackage(batch);
            LoginSent = true;
        }
コード例 #5
0
		public void TestUuid()
		{
			var rfc4122Bytes = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
			UUID uuid = new UUID(rfc4122Bytes);
			Assert.AreEqual(rfc4122Bytes, uuid.GetBytes());

			Skin skin = new Skin {Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))};
			var packet = new McpeLogin()
			{
				username = "******",
				protocol = 34,
				protocol2 = 34,
				clientId = new Random().Next(),
				clientUuid = new UUID(Guid.NewGuid().ToByteArray()),
				serverAddress = "83.249.65.92:19132",
				clientSecret = "iwmvi45hm85oncyo58",
				skin = skin,
			};

			var bytes = packet.Encode();
			Console.WriteLine(Package.HexDump(bytes, 16));

			UUID uuid2 = new UUID(rfc4122Bytes);

			Dictionary<UUID, string> uuiDictionary = new Dictionary<UUID, string>();
			uuiDictionary.Add(uuid, "test");

			Assert.AreEqual("test", uuiDictionary[uuid2]);
			
		}
コード例 #6
0
        public virtual void HandleMcpeLogin(McpeLogin message)
        {
            // Only one login!
            lock (_loginSyncLock)
            {
                if (_session.Username != null)
                {
                    Log.Info($"Player {_session.Username} doing multiple logins");
                    return;                     // Already doing login
                }

                _session.Username = string.Empty;
            }

            if (message.protocolVersion < 111)
            {
                Log.Warn($"Wrong version ({message.protocolVersion}) of Minecraft Pocket Edition, client need an upgrade.");
                _session.Disconnect($"Wrong version ({message.protocolVersion}) of Minecraft Pocket Edition, please upgrade.");
                return;
            }

            DecodeCert(message);
            _playerInfo.Edition = message.edition;

            ////string fileName = Path.GetTempPath() + "Skin_" + Skin.SkinType + ".png";
            ////Log.Info($"Writing skin to filename: {fileName}");
            ////Skin.SaveTextureToFile(fileName, Skin.Texture);
        }
コード例 #7
0
ファイル: MinetServerTest.cs プロジェクト: CavinMiana/MiNET
        public void TestUuid()
        {
            var  rfc4122Bytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
            UUID uuid         = new UUID(rfc4122Bytes);

            Assert.AreEqual(rfc4122Bytes, uuid.GetBytes());

            Skin skin = new Skin {
                Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))
            };
            var packet = new McpeLogin()
            {
                username      = "******",
                protocol      = 34,
                protocol2     = 34,
                clientId      = new Random().Next(),
                clientUuid    = new UUID(),
                serverAddress = "83.249.65.92:19132",
                clientSecret  = "iwmvi45hm85oncyo58",
                skin          = skin,
            };

            var bytes = packet.Encode();

            Console.WriteLine(Package.HexDump(bytes, 16));
        }
コード例 #8
0
        public virtual void HandleMcpeLogin(McpeLogin message)
        {
            //Disconnect("Este servidor ya no existe. Por favor, conecta a " + ChatColors.Aqua + "play.bladestorm.net" + ChatColors.White + " para seguir jugando.");
            ////Disconnect("This server is closed. Please connect to " + ChatColors.Aqua + "play.bladestorm.net" + ChatColors.White + " to continue playing.");
            //return;

            // Only one login!
            lock (_loginSyncLock)
            {
                if (_session.Username != null)
                {
                    Log.Info($"Player {_session.Username} doing multiple logins");
                    return;                     // Already doing login
                }

                _session.Username = string.Empty;
            }

            if (message.protocolVersion < 111)
            {
                Log.Warn($"Wrong version ({message.protocolVersion}) of Minecraft Pocket Edition, client need an upgrade.");
                _session.Disconnect($"Wrong version ({message.protocolVersion}) of Minecraft Pocket Edition, please upgrade.");
                return;
            }

            // THIS counter exist to protect the level from being swamped with player list add
            // attempts during startup (normally).

            DecodeCert(message);
            _playerInfo.Edition = message.edition;

            //if (!message.username.Equals("gurun") && !message.username.Equals("TruDan") && !message.username.Equals("Morehs"))
            //{
            //	if (serverInfo.NumberOfPlayers > serverInfo.MaxNumberOfPlayers)
            //	{
            //		Disconnect("Too many players (" + serverInfo.NumberOfPlayers + ") at this time, please try again.");
            //		return;
            //	}

            //	// Use for loadbalance only right now.
            //	if (serverInfo.ConnectionsInConnectPhase > serverInfo.MaxNumberOfConcurrentConnects)
            //	{
            //		Disconnect("Too many concurrent logins (" + serverInfo.ConnectionsInConnectPhase + "), please try again.");
            //		return;
            //	}
            //}

            //if (message.username == null || message.username.Trim().Length == 0 || !Regex.IsMatch(message.username, "^[A-Za-z0-9_-]{3,56}$"))
            //{
            //	Disconnect("Invalid username.");
            //	return;
            //}

            ////string fileName = Path.GetTempPath() + "Skin_" + Skin.SkinType + ".png";
            ////Log.Info($"Writing skin to filename: {fileName}");
            ////Skin.SaveTextureToFile(fileName, Skin.Texture);
        }
コード例 #9
0
 public Package HandleJoin(McpeLogin packet, Player player)
 {
     player.SpawnPosition = new PlayerLocation(spawnPos);
     player.HealthManager = new PlayerHealthManager(player, this);
     // show a little welcome message
     player.AddPopup(new Popup()
     {
         MessageType = MessageType.Tip,
         Message     = "§aWelcome on MiniPE!",
         Duration    = 30
     });
     return(packet);
 }
コード例 #10
0
        public void onBan(McpeLogin package, Player player)
        {
            string          sql  = string.Format("SELECT admin, reason, time FROM banip WHERE player='{0}' OR ip='{1}' OR clientid='{2}';", player.Username.ToLower(), player.EndPoint.Address, GenerateMD5Hash(player.ClientUuid.ToString()));
            List <object[]> rows = Database.ExecuteQuery(sql);

            if (rows == null || !rows.Any())
            {
                return;
            }
            if (rows[0][0].ToString() != null)
            {
                //Log.Info (rows);
                int time = Convert.ToInt32(rows[0][2].ToString()) / 86400;
                player.Disconnect(string.Format(LangManager.getLang(Pool.getPlayer(player).lang).getString("authme.ban.message.banned"), rows[0][0].ToString(), time, rows[0][1].ToString()), true);
            }
        }
コード例 #11
0
ファイル: Kits.cs プロジェクト: Mangadze/Plugins
        public Package McpeLogin(McpeLogin packet, Player player)
        {
            if (PlayersKitActivated.Contains(player.Username))
            {
                PlayersKitActivated.Remove(player.Username);
            }

            player.SendMessage(string.Format(ChatColors.Yellow + "Welcome " + player.Username), type: MessageType.Chat);

            player.AddPopup(new Popup()
            {
                Message  = $"{ChatColors.Gold}Fury Is Godly At C# ~ USER: " + player.Username,
                Duration = 99999999,
                Priority = 1000
            });

            return(packet);
        }
コード例 #12
0
        public Package PlayerJoinPacket(McpeLogin login, Player player)
        {
            if (!MiNETEssentials.playerConfig.ContainsKey(login.username))
            {
                JObject obj = new JObject();
                obj["username"] = login.username;
                obj["lastjoin"] = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();

                MiNETEssentials.playerConfig.Add(login.username, obj);

                MiNETEssentials.SavePlayerConfig();

                MiNETEssentials.Log.Info(login.username + " has joined for the first time!");
            }
            else
                MiNETEssentials.Log.Info(login.username + " has joined! Last joined: " + (string)MiNETEssentials.playerConfig[login.username]["lastjoin"]);

            return login;
        }
コード例 #13
0
        public void SendLogin(string username)
        {
            Skin skin = new Skin {
                Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))
            };
            var packet = new McpeLogin()
            {
                clientId = 12345,
                username = username,
                protocol = 27,
                skin     = skin
            };

            McpeBatch batch = new McpeBatch();

            byte[] buffer = CompressBytes(packet.Encode());

            batch.payloadSize = buffer.Length;
            batch.payload     = buffer;

            SendPackage(batch);
        }
コード例 #14
0
        public virtual void HandleMcpeLogin(McpeLogin message)
        {
            // Only one login!
            lock (_loginSyncLock)
            {
                if (_session.Username != null)
                {
                    Log.Info($"Player {_session.Username} doing multiple logins");
                    return;                     // Already doing login
                }

                _session.Username = string.Empty;
            }

            _playerInfo.ProtocolVersion = message.protocolVersion;
            //_playerInfo.Edition = message.;

            DecodeCert(message);

            ////string fileName = Path.GetTempPath() + "Skin_" + Skin.SkinType + ".png";
            ////Log.Info($"Writing skin to filename: {fileName}");
            ////Skin.SaveTextureToFile(fileName, Skin.Texture);
        }
コード例 #15
0
        protected void DecodeCert(McpeLogin message)
        {
            byte[] buffer = message.payload;

            if (message.payload.Length != buffer.Length)
            {
                Log.Debug($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
                throw new Exception($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
            }

            if (Log.IsDebugEnabled)
            {
                Log.Debug("Lenght: " + message.payload.Length + ", Message: " + Convert.ToBase64String(buffer));
            }

            string certificateChain;
            string skinData;

            try
            {
                var destination = new MemoryStream(buffer);
                destination.Position = 0;
                NbtBinaryReader reader = new NbtBinaryReader(destination, false);

                var countCertData = reader.ReadInt32();
                certificateChain = Encoding.UTF8.GetString(reader.ReadBytes(countCertData));
                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Certificate Chain (Lenght={countCertData})\n{certificateChain}");
                }

                var countSkinData = reader.ReadInt32();
                skinData = Encoding.UTF8.GetString(reader.ReadBytes(countSkinData));
                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Skin data (Lenght={countSkinData})\n{skinData}");
                }
            }
            catch (Exception e)
            {
                Log.Error("Parsing login", e);
                return;
            }

            try
            {
                {
                    IDictionary <string, dynamic> headers = JWT.Headers(skinData);
                    dynamic payload = JObject.Parse(JWT.Payload(skinData));

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Header: {string.Join(";", headers)}");
                    }
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Payload:\n{payload.ToString()}");
                    }

                    try
                    {
                        _playerInfo.ClientId         = payload.ClientRandomId;
                        _playerInfo.CurrentInputMode = payload.CurrentInputMode;
                        _playerInfo.DefaultInputMode = payload.DefaultInputMode;
                        _playerInfo.DeviceModel      = payload.DeviceModel;
                        _playerInfo.DeviceOS         = payload.DeviceOS;
                        _playerInfo.GameVersion      = payload.GameVersion;
                        _playerInfo.GuiScale         = payload.GuiScale;
                        _playerInfo.LanguageCode     = payload.LanguageCode;
                        _playerInfo.ServerAddress    = payload.ServerAddress;
                        _playerInfo.UIProfile        = payload.UIProfile;

                        _playerInfo.Skin = new Skin()
                        {
                            CapeData         = Convert.FromBase64String((string)payload.CapeData),
                            SkinId           = payload.SkinId,
                            SkinData         = Convert.FromBase64String((string)payload.SkinData),
                            SkinGeometryName = payload.SkinGeometryName,
                            SkinGeometry     = Convert.FromBase64String((string)payload.SkinGeometry),
                        };
                        Log.Warn($"Cape data lenght={_playerInfo.Skin.CapeData.Length}");
                    }
                    catch (Exception e)
                    {
                        Log.Error("Parsing skin data", e);
                    }
                }

                {
                    dynamic json = JObject.Parse(certificateChain);

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Certificate JSON:\n{json}");
                    }

                    JArray chain = json.chain;
                    //var chainArray = chain.ToArray();

                    string validationKey     = null;
                    string identityPublicKey = null;

                    foreach (JToken token in chain)
                    {
                        IDictionary <string, dynamic> headers = JWT.Headers(token.ToString());

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug("Raw chain element:\n" + token.ToString());
                            Log.Debug($"JWT Header: {string.Join(";", headers)}");

                            dynamic jsonPayload = JObject.Parse(JWT.Payload(token.ToString()));
                            Log.Debug($"JWT Payload:\n{jsonPayload}");
                        }

                        // Mojang root x5u cert (string): MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V

                        if (!headers.ContainsKey("x5u"))
                        {
                            continue;
                        }

                        string x5u = headers["x5u"];

                        if (identityPublicKey == null)
                        {
                            if (CertificateData.MojangRootKey.Equals(x5u, StringComparison.InvariantCultureIgnoreCase))
                            {
                                Log.Debug("Key is ok, and got Mojang root");
                            }
                            else if (chain.Count > 1)
                            {
                                Log.Debug("Got client cert (client root)");
                                continue;
                            }
                            else if (chain.Count == 1)
                            {
                                Log.Debug("Selfsigned chain");
                            }
                        }
                        else if (identityPublicKey.Equals(x5u))
                        {
                            Log.Debug("Derived Key is ok");
                        }

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug($"x5u cert (string): {x5u}");
                            ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(x5u);
                            Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                        }

                        // Validate
                        CngKey          newKey = CryptoUtils.ImportECDsaCngKeyFromString(x5u);
                        CertificateData data   = JWT.Decode <CertificateData>(token.ToString(), newKey);

                        if (data != null)
                        {
                            identityPublicKey = data.IdentityPublicKey;

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug("Decoded token success");
                            }

                            if (CertificateData.MojangRootKey.Equals(x5u, StringComparison.InvariantCultureIgnoreCase))
                            {
                                Log.Debug("Got Mojang key. Is valid = " + data.CertificateAuthority);
                                validationKey = data.IdentityPublicKey;
                            }
                            else if (validationKey != null && validationKey.Equals(x5u, StringComparison.InvariantCultureIgnoreCase))
                            {
                                _playerInfo.CertificateData = data;
                            }
                            else
                            {
                                if (data.ExtraData == null)
                                {
                                    continue;
                                }

                                // Self signed, make sure they don't fake XUID
                                if (data.ExtraData.Xuid != null)
                                {
                                    Log.Warn("Received fake XUID from " + data.ExtraData.DisplayName);
                                    data.ExtraData.Xuid = null;
                                }

                                _playerInfo.CertificateData = data;
                            }
                        }
                        else
                        {
                            Log.Error("Not a valid Identity Public Key for decoding");
                        }
                    }

                    //TODO: Implement disconnect here

                    {
                        _playerInfo.Username = _playerInfo.CertificateData.ExtraData.DisplayName;
                        _session.Username    = _playerInfo.Username;
                        string identity = _playerInfo.CertificateData.ExtraData.Identity;

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug($"Connecting user {_playerInfo.Username} with identity={identity}");
                        }
                        _playerInfo.ClientUuid = new UUID(identity);

                        _session.CryptoContext = new CryptoContext
                        {
                            UseEncryption = Config.GetProperty("UseEncryptionForAll", false) || (Config.GetProperty("UseEncryption", true) && !string.IsNullOrWhiteSpace(_playerInfo.CertificateData.ExtraData.Xuid)),
                        };

                        if (_session.CryptoContext.UseEncryption)
                        {
                            ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(_playerInfo.CertificateData.IdentityPublicKey);
                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                            }

                            // Create shared shared secret
                            ECDiffieHellmanCng ecKey = new ECDiffieHellmanCng(384);
                            ecKey.HashAlgorithm         = CngAlgorithm.Sha256;
                            ecKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                            ecKey.SecretPrepend         = Encoding.UTF8.GetBytes("RANDOM SECRET");                     // Server token

                            byte[] secret = ecKey.DeriveKeyMaterial(publicKey);

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"SECRET KEY (b64):\n{Convert.ToBase64String(secret)}");
                            }

                            {
                                RijndaelManaged rijAlg = new RijndaelManaged
                                {
                                    BlockSize    = 128,
                                    Padding      = PaddingMode.None,
                                    Mode         = CipherMode.CFB,
                                    FeedbackSize = 8,
                                    Key          = secret,
                                    IV           = secret.Take(16).ToArray(),
                                };

                                // Create a decrytor to perform the stream transform.
                                ICryptoTransform decryptor      = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream     inputStream    = new MemoryStream();
                                CryptoStream     cryptoStreamIn = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read);

                                ICryptoTransform encryptor       = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream     outputStream    = new MemoryStream();
                                CryptoStream     cryptoStreamOut = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);

                                _session.CryptoContext.Algorithm       = rijAlg;
                                _session.CryptoContext.Decryptor       = decryptor;
                                _session.CryptoContext.Encryptor       = encryptor;
                                _session.CryptoContext.InputStream     = inputStream;
                                _session.CryptoContext.OutputStream    = outputStream;
                                _session.CryptoContext.CryptoStreamIn  = cryptoStreamIn;
                                _session.CryptoContext.CryptoStreamOut = cryptoStreamOut;
                            }

                            //TODO: JSON now.
                            throw new Exception("JSON!!!");
                            //var response = McpeServerToClientHandshake.CreateObject();
                            //	response.NoBatch = true;
                            //	response.ForceClear = true;

                            //response.token =
                            //	response.serverPublicKey = Convert.ToBase64String(ecKey.PublicKey.GetDerEncoded());
                            //	response.tokenLength = (short) ecKey.SecretPrepend.Length;
                            //	response.token = ecKey.SecretPrepend;

                            //_session.SendPackage(response);

                            if (Log.IsDebugEnabled)
                            {
                                Log.Warn($"Encryption enabled for {_session.Username}");
                            }
                        }
                    }
                }

                if (!_session.CryptoContext.UseEncryption)
                {
                    _session.MessageHandler.HandleMcpeClientToServerHandshake(null);
                }
            }
            catch (Exception e)
            {
                Log.Error("Decrypt", e);
            }
        }
コード例 #16
0
ファイル: Player.cs プロジェクト: Creeperface01/MiNET
        protected virtual void HandleLogin(McpeLogin message)
        {
            Stopwatch watch = new Stopwatch();
            watch.Restart();

            // Only one login!
            lock (_loginSyncLock)
            {
                if (Username != null)
                {
                    Log.DebugFormat("Player {0} doing multiple logins on Level: {1}", Username, Level.LevelId);
                    return; // Already doing login
                }
                Username = message.username;
            }

            if (message.protocol != 27)
            {
                Disconnect("Outdated Minecraft Pocket Edition, please upgrade.");
                return;
            }

            var serverInfo = Server.ServerInfo;

            if (!message.username.Equals("gurun") && !message.username.Equals("TruDan"))
            {
                if (serverInfo.NumberOfPlayers > serverInfo.MaxNumberOfPlayers)
                {
                    Disconnect("Too many players (" + serverInfo.NumberOfPlayers + ") at this time, please try again.");
                    return;
                }

                // Use for loadbalance only right now.
                if (serverInfo.ConnectionsInConnectPhase > serverInfo.MaxNumberOfConcurrentConnects)
                {
                    Disconnect("Too many concurrent logins (" + serverInfo.ConnectionsInConnectPhase + "), please try again.");
                    return;
                }
            }

            if (message.username == null || message.username.Trim().Length == 0 || !Regex.IsMatch(message.username, "^[A-Za-z0-9_-]{3,16}$"))
            {
                Disconnect("Invalid username.");
                return;
            }

            if (message.skin.Texture == null)
            {
                Disconnect("Invalid skin.");
                return;
            }

            try
            {
                Interlocked.Increment(ref serverInfo.ConnectionsInConnectPhase);

                SendPlayerStatus(0);

                Username = message.username;
                ClientId = message.clientId;

                // Check if the user already exist, that case bumpt the old one
                Level.RemoveDuplicatePlayers(Username, ClientId);

                Level.EntityManager.AddEntity(null, this);

                Session = Server.SessionManager.CreateSession(this);
                if (Server.IsSecurityEnabled)
                {
                    User = Server.UserManager.FindByName(Username);
                }

                Skin = message.skin;

                // Start game

                SendStartGame();

                SendSetSpawnPosition();

                SendSetTime();

                SendSetDificulty();

                SendAdventureSettings();

                SendSetHealth();

                SendSetEntityData();

                Level.AddPlayer(this, string.Format("{0} joined the game!", Username), false);

                LastUpdatedTime = DateTime.UtcNow;

                SendPlayerInventory();

                ThreadPool.QueueUserWorkItem(delegate(object state)
                {
                    Level.SpawnToAll(this);
                    SendChunksForKnownPosition();
                });

                LastUpdatedTime = DateTime.UtcNow;
                Log.InfoFormat("Login complete by: {0} from {2} in {1}ms", message.username, watch.ElapsedMilliseconds, EndPoint);
            }
            finally
            {
                Interlocked.Decrement(ref serverInfo.ConnectionsInConnectPhase);
            }
        }
コード例 #17
0
ファイル: MiNetClient.cs プロジェクト: andrewhutche/MiNET
        public void SendLogin(string username)
        {
            Skin skin = new Skin {Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))};
            skin.SkinType = "Standard_Custom";
            //Skin skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 16384)) };
            var packet = new McpeLogin()
            {
                username = username,
                protocol = 39,
                protocol2 = 39,
                clientId = ClientId,
                clientUuid = new UUID(Guid.NewGuid().ToByteArray()),
                serverAddress = _serverEndpoint.Address + ":" + _serverEndpoint.Port,
                clientSecret = "iwmvi45hm85oncyo58",
                //clientSecret = Encoding.ASCII.GetString(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("" + ClientId + _serverEndpoint.Address + _serverEndpoint.Port))),
                skin = skin,
            };

            byte[] buffer = Player.CompressBytes(packet.Encode(), CompressionLevel.Fastest, true);

            McpeBatch batch = new McpeBatch();
            batch.payloadSize = buffer.Length;
            batch.payload = buffer;
            batch.Encode();

            SendPackage(batch);
            LoginSent = true;
        }
コード例 #18
0
ファイル: Player.cs プロジェクト: MrGenga/MiNET
		protected virtual void HandleLogin(McpeLogin message)
		{
			//Disconnect("Este servidor ya no existe. Por favor, conecta a " + ChatColors.Aqua + "play.bladestorm.net" + ChatColors.White + " para seguir jugando.");
			////Disconnect("This server is closed. Please connect to " + ChatColors.Aqua + "play.bladestorm.net" + ChatColors.White + " to continue playing.");
			//return;

			// Only one login!
			lock (_loginSyncLock)
			{
				if (Username != null)
				{
					Log.InfoFormat("Player {0} doing multiple logins", Username);
					return; // Already doing login
				}

				Username = message.username;
			}

			if (message.protocol < 43)
			{
				Server.GreylistManager.Greylist(EndPoint.Address, 30000);
				Disconnect($"Wrong version ({message.protocol}) of Minecraft Pocket Edition, please upgrade.");
				return;
			}

			//if (!message.username.Equals("gurun") && !message.username.Equals("TruDan") && !message.username.Equals("Morehs"))
			//{
			//	if (serverInfo.NumberOfPlayers > serverInfo.MaxNumberOfPlayers)
			//	{
			//		Disconnect("Too many players (" + serverInfo.NumberOfPlayers + ") at this time, please try again.");
			//		return;
			//	}

			//	// Use for loadbalance only right now.
			//	if (serverInfo.ConnectionsInConnectPhase > serverInfo.MaxNumberOfConcurrentConnects)
			//	{
			//		Disconnect("Too many concurrent logins (" + serverInfo.ConnectionsInConnectPhase + "), please try again.");
			//		return;
			//	}
			//}

			if (message.username == null || message.username.Trim().Length == 0 || !Regex.IsMatch(message.username, "^[A-Za-z0-9_-]{3,16}$"))
			{
				Disconnect("Invalid username.");
				return;
			}

			if (string.IsNullOrEmpty(message.skin.SkinType) || message.skin.Texture == null)
			{
				Disconnect("Invalid skin. Please upgrade your version of Minecraft Pocket Edition");
				return;
			}

			SendPlayerStatus(0); // Hmm, login success?

			Username = message.username;
			ClientId = (int) message.clientId;
			ClientUuid = message.clientUuid;
			ClientSecret = message.clientSecret;
			Skin = message.skin;

			Log.Warn("ClientSecret: " + ClientSecret);

			//string fileName = Path.GetTempPath() + "Skin_" + Skin.SkinType + ".png";
			//Log.Info($"Writing skin to filename: {fileName}");
			//Skin.SaveTextureToFile(fileName, Skin.Texture);

			var serverInfo = Server.ServerInfo;

			if (ClientSecret != null)
			{
				var count = serverInfo.PlayerSessions.Values.Count(session => session.Player != null && ClientSecret.Equals(session.Player.ClientSecret));
				if (count != 1)
				{
					Disconnect($"Invalid skin {count}.");
					return;
				}
			}

			// THIS counter exist to protect the level from being swamped with player list add
			// attempts during startup (normally).
			Interlocked.Increment(ref serverInfo.ConnectionsInConnectPhase);

			new Thread(Start).Start();
		}
コード例 #19
0
 public override void HandleMcpeLogin(McpeLogin message)
 {
     base.HandleMcpeLogin(message);
 }
コード例 #20
0
ファイル: Player.cs プロジェクト: Hetal728/MiNET
        /// <summary>
        ///     Handles the login.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <exception cref="System.Exception">
        ///     No username on login
        ///     or
        ///     No username on login
        /// </exception>
        protected virtual void HandleLogin(McpeLogin message)
        {
            if (Username != null) return; // Already doing login

            Username = message.username;
            ClientId = message.clientId;

            User user = Server.UserManager.FindByName(Username);
            if (user != null)
            {
                Session = Server.SessionManager.FindSession(EndPoint, ClientId, Username);
                if (Session != null)
                {
                    User = user;
                }
            }

            Skin = message.skin;
            //Skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192)) };

            Log.WarnFormat("Login attempt by: {0}", Username);

            if (Username.Trim().Length == 0)
            {
                SendPackage(new McpePlayerStatus {status = 2});
                return;
            }

            // Check if the user already exist, that case bumpt the old one
            Level.RemoveDuplicatePlayers(Username);

            if (Username.StartsWith("Player")) IsBot = true; // HACK

            if (Username.StartsWith("Wix")) return;
            if (Username.StartsWith("Wiz")) return;
            if (Username.StartsWith("Aga")) return;

            // Start game

            Level.EntityManager.AddEntity(null, this);

            // We send a ping here to get an initial value for chunk-sending
            _pingSendTime = DateTime.UtcNow.Ticks/TimeSpan.TicksPerMillisecond;
            SendPackage(new ConnectedPing {sendpingtime = _pingSendTime});

            SendPackage(new McpePlayerStatus {status = 0});
            SendStartGame();
            SendSetSpawnPosition();
            SendSetTime();
            SendPackage(new McpeSetDifficulty {difficulty = (int) Level.Difficulty});
            SendPackage(new McpeAdventureSettings {flags = Level.IsSurvival ? 0x20 : 0x80});
            //SendPackage(new McpeAdventureSettings { flags = Level.IsSurvival ? 0x80 : 0x80 });
            SendSetHealth();

            SendPackage(new McpeSetEntityData
            {
                entityId = EntityId,
                metadata = GetMetadata()
            });

            Level.AddPlayer(this, string.Format("{0} joined the game!", Username));

            SendPackage(new McpeContainerSetContent
            {
                windowId = 0,
                slotData = Inventory.Slots,
                hotbarData = Inventory.ItemHotbar
            });

            SendPackage(new McpeContainerSetContent
            {
                windowId = 0x78, // Armor windows ID
                slotData = Inventory.Armor,
                hotbarData = null
            });

            //SendPackage(new McpePlayerStatus {status = 3});

            SendChunksForKnownPosition();

            //IsSpawned = true;

            LastUpdatedTime = DateTime.UtcNow;
        }
コード例 #21
0
        protected void DecodeCert(McpeLogin message)
        {
            // Get bytes
            byte[] buffer = message.payload;

            //Log.Debug($"Unknown byte in login packet is: {message.unknown}");

            if (message.payload.Length != buffer.Length)
            {
                Log.Debug($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
                throw new Exception($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
            }
            // Decompress bytes

            Log.Debug("Lenght: " + message.payload.Length + ", Message: " + Convert.ToBase64String(buffer));

            //MemoryStream stream = new MemoryStream(buffer);
            //if (stream.ReadByte() != 0x78)
            //{
            //	throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C");
            //}
            //stream.ReadByte();

            string certificateChain;
            string skinData;

            //using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false))
            {
                // Get actual package out of bytes
                //using (MemoryStream destination = MiNetServer.MemoryStreamManager.GetStream())
                {
                    //defStream2.CopyTo(destination);

                    var destination = new MemoryStream(buffer);
                    destination.Position = 0;
                    NbtBinaryReader reader = new NbtBinaryReader(destination, false);

                    try
                    {
                        var countCertData = reader.ReadInt32();
                        Log.Debug("Count cert: " + countCertData);
                        certificateChain = Encoding.UTF8.GetString(reader.ReadBytes(countCertData));
                        Log.Debug("Decompressed certificateChain " + certificateChain);

                        var countSkinData = reader.ReadInt32();
                        Log.Debug("Count skin: " + countSkinData);
                        skinData = Encoding.UTF8.GetString(reader.ReadBytes(countSkinData));
                        Log.Debug("Decompressed skinData" + skinData);
                    }
                    catch (Exception e)
                    {
                        Log.Error("Parsing login", e);
                        return;
                    }
                }
            }


            try
            {
                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("Input SKIN string: " + skinData);
                    }

                    IDictionary <string, dynamic> headers = JWT.Headers(skinData);
                    dynamic payload = JObject.Parse(JWT.Payload(skinData));

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Header: {string.Join(";", headers)}");
                    }
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Payload:\n{payload.ToString()}");
                    }

                    Console.WriteLine(payload);
                    // Skin JWT Payload:

                    //{
                    //	"ClientRandomId": 1423700530444426768,
                    //	"CurrentInputMode": 1,
                    //	"DefaultInputMode": 1,
                    //	"DeviceModel": "ASUSTeK COMPUTER INC. N550JK",
                    //	"DeviceOS": 7,
                    //	"GameVersion": "1.2.0",
                    //	"GuiScale": 0,
                    //	"LanguageCode": "en_US",
                    //	"ServerAddress": "192.168.0.3:19132",
                    //	"SkinData": "SnNH/1+KUf97n2T/AAAAAAAAAAAAAAAAAAAAAAAAAACWlY//q6ur/5aVj/+WlY//q6ur/5aVj/+WlY//q6ur/1JSUv9zbmr/c25q/1JSUv9zbmr/UlJS/3Nuav9zbmr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBfQ/+WlY//q6ur/7+/v/8AAAAAAAAAAAAAAAAAAAAAQF9D/0pzR/9filH/SnNH/0BfQ/9Kc0f/SnNH/0BfQ/9zbmr/c25q/3Nuav9SUlL/c25q/1JSUv9zbmr/c25q/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7Sz7/c25q/1QxKP9wTTr/jGVJ/wAAAAAAAAAAAAAAAEpzR/9Kc0f/X4pR/1+KUf9Kc0f/SnNH/1+KUf9Kc0f/UlJS/1JSUv9SUlL/UlJS/1JSUv9SUlL/UlJS/3Nuav8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFJSUv87IBz/AAAAAAAAAAAAAAAAAAAAAAAAAABfilH/X4pR/1+KUf9filH/X4pR/1+KUf9Kc0f/X4pR/ztLPv87Sz7/O0s+/ztLPv87Sz7/O0s+/ztLPv87Sz7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIRMT/wAAAAAAAAAAAAAAAAAAAAAAAAAAX4pR/1+KUf9filH/e59k/1+KUf9filH/SnNH/1+KUf87Sz7/O0s+/ztLPv87Sz7/O0s+/ztLPv87Sz7/O0s+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpzR/9Kc0f/X4pR/1+KUf9filH/SnNH/0BfQ/9Kc0f/O0s+/ztLPv87Sz7/O0s+/ztLPv87Sz7/O0s+/ztLPv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKc0f/QF9D/0pzR/9filH/X4pR/0pzR/9AX0P/SnNH/0BfQ/87Sz7/QF9D/0BfQ/9AX0P/QF9D/ztLPv9AX0P/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQF9D/0pzR/9filH/X4pR/1+KUf9filH/SnNH/0BfQ/9AX0P/QF9D/0pzR/9Kc0f/SnNH/0pzR/9AX0P/QF9D/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACrq6v/QF9D/0pzR/9filH/X4pR/0pzR/9Kc0f/QF9D/0BfQ/9Kc0f/X4pR/1+KUf9filH/X4pR/0pzR/9AX0P/QF9D/0pzR/9Kc0f/X4pR/1+KUf9Kc0f/QF9D/5aVj/+rq6v/lpWP/5aVj/+rq6v/lpWP/5aVj/+rq6v/lpWP/1+KUf9filH/X4pR/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF+KUf9filH/X4pR/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq6ur/6urq/9filH/e59k/1+KUf9filH/SnNH/0pzR/9Kc0f/SnNH/0pzR/9filH/X4pR/0pzR/9Kc0f/SnNH/0pzR/9Kc0f/X4pR/1+KUf97n2T/X4pR/6urq/+WlY//q6ur/6urq/+WlY//lpWP/6urq/+WlY//q6ur/5aVj/9filH/QF9D/0pzR/9filH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF+KUf9Kc0f/QF9D/1+KUf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJaVj/+rq6v/X4pR/1+KUf9filH/SnNH/0BfQ/9AX0P/QF9D/0BfQ/9Kc0f/SnNH/0pzR/9Kc0f/QF9D/0BfQ/9AX0P/QF9D/0pzR/9filH/X4pR/1+KUf+rq6v/lpWP/5aVj/+rq6v/q6ur/5aVj/+WlY//q6ur/6urq/+rq6v/AAAAAEBfQ/9Kc0f/QF9D/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAX0P/SnNH/0BfQ/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzbmr/q6ur/0pzR/9filH/SnNH/0pzR/9AX0P/SnNH/0BfQ//Z2dD/AAAA/1+KUf9AX0P/AAAA/9nZ0P9AX0P/SnNH/0BfQ/9Kc0f/SnNH/1+KUf9Kc0f/q6ur/6urq/9zbmr/q6ur/6urq/+rq6v/lpWP/6urq/+WlY//q6ur/wAAAABKc0f/X4pR/0pzR/9AX0P/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAX0P/SnNH/1+KUf9Kc0f/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc25q/5aVj/9AX0P/X4pR/1+KUf9Kc0f/QF9D/1+KUf9AX0P/X4pR/1+KUf9Kc0f/QF9D/1+KUf9filH/QF9D/1+KUf9AX0P/SnNH/1+KUf9filH/QF9D/5aVj/+rq6v/c25q/5aVj/+WlY//q6ur/3Nuav+rq6v/lpWP/5aVj/8AAAAAAAAAAEpzR/9AX0P/QF9D/0pzR/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKc0f/QF9D/0BfQ/9Kc0f/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFJSUv+rq6v/lpWP/1+KUf9Kc0f/X4pR/0pzR/9filH/X4pR/1+KUf9Kc0f/SnNH/0pzR/9Kc0f/X4pR/1+KUf9filH/SnNH/1+KUf9Kc0f/X4pR/6urq/+WlY//q6ur/1JSUv+WlY//c25q/6urq/9zbmr/lpWP/6urq/9zbmr/AAAAAAAAAAAAAAAASnNH/0BfQ/9AX0P/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQF9D/0BfQ/9Kc0f/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSUlL/lpWP/3Nuav+WlY//QF9D/0pzR/9Kc0f/SnNH/0pzR/9Kc0f/SnNH/wAAAP8AAAD/SnNH/0pzR/9Kc0f/SnNH/0pzR/9Kc0f/QF9D/5aVj/+rq6v/c25q/5aVj/9SUlL/c25q/3Nuav+WlY//UlJS/5aVj/+rq6v/c25q/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUlJS/5aVj/9SUlL/lpWP/1JSUv87Sz7/QF9D/0BfQ/9AX0P/QF9D/0pzR/9Kc0f/SnNH/0pzR/9AX0P/QF9D/0BfQ/9AX0P/O0s+/5aVj/9zbmr/lpWP/3Nuav+WlY//UlJS/3Nuav9SUlL/c25q/1JSUv9zbmr/lpWP/1JSUv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0Y1T/UktM/1JLTP9SS0z/SnNH/0pzR/9AX0P/O0s+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUktM/5eQcv90Y1T/UktM/1JLTP90Y1T/l5By/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqqma/5eQcv+XkHL/dGNU/0BfQ/9AX0P/O0s+/0pzR/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl5By/3RjVP9SS0z/UktM/0pzR/9AX0P/O0s+/ztLPv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFJLTP8hExP/IRMT/yETE/8hExP/IRMT/yETE/9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqpmv+qqZr/qqma/5eQcv9Kc0f/v7+4/0BfQ/9AX0P/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeQcv90Y1T/UktM/zsgHP9Kc0f/QF9D/ztLPv87Sz7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSS0z/IRMT/yETE/8hExP/IRMT/yETE/8hExP/UktM/1JLTP9SS0z/UktM/yETE/8hExP/UktM/1JLTP9SS0z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqqZr/qqma/6qpmv+XkHL/QF9D/0BfQ/87Sz7/QF9D/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0Y1T/UktM/1JLTP87IBz/QF9D/0pzR/9AX0P/O0s+/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUktM/yETE/8hExP/IRMT/yETE/8hExP/IRMT/1JLTP9SS0z/UktM/1JLTP87IBz/IRMT/1JLTP9SS0z/UktM/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqqma/5eQcv+XkHL/dGNU/0pzR/+/v7j/QF9D/0pzR/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXkHL/c2Rk/3NkZP+XkHL/l5By/3RjVP9SS0z/IRMT/yETE/8hExP/UktM/1JLTP9SS0z/UktM/3RjVP+XkHL/dGNU/1JLTP9SS0z/UktM/1JLTP8hExP/IRMT/zsgHP87IBz/IRMT/yETE/9SS0z/UktM/1JLTP9SS0z/dGNU/3RjVP+qqZr/l5By/3RjVP90Y1T/l5By/6qpmv90Y1T/qqma/7+/uP+/v7j/qqma/6qpmv+XkHL/dGNU/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/3RjVP+XkHL/qqma/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl5By/3NkZP9zZGT/l5By/6qpmv+XkHL/dGNU/yETE/8hExP/IRMT/1JLTP9SS0z/UktM/3RjVP+XkHL/qqma/5eQcv90Y1T/UktM/1JLTP90Y1T/OyAc/1QxKP9UMSj/VDEo/1QxKP87IBz/dGNU/1JLTP9SS0z/dGNU/5eQcv+qqZr/v7+4/6qpmv+XkHL/l5By/6qpmv+/v7j/qqma/7+/uP+/v7j/v7+4/7+/uP+/v7j/qqma/5eQcv9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP+XkHL/qqma/7+/uP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqpmv9zZGT/c2Rk/6qpmv+qqZr/l5By/3RjVP87IBz/IRMT/yETE/9SS0z/UktM/1JLTP+XkHL/qqma/6qpmv+XkHL/dGNU/1JLTP90Y1T/l5By/1QxKP9wTTr/cE06/3BNOv9wTTr/OyAc/5eQcv90Y1T/UktM/3RjVP+XkHL/qqma/6qpmv90Y1T/qqma/6qpmv90Y1T/qqma/6qpmv+qqZr/v7+4/7+/uP+qqZr/qqma/6qpmv+XkHL/dGNU/1JLTP9SS0z/UktM/1JLTP90Y1T/l5By/6qpmv+qqZr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqqZr/c2Rk/7+/uP+qqZr/qqma/6qpmv+XkHL/OyAc/yETE/8hExP/UktM/1JLTP90Y1T/l5By/6qpmv+qqZr/dGNU/1JLTP90Y1T/l5By/6qpmv87IBz/cE06/4xlSf9wTTr/VDEo/zsgHP+qqZr/l5By/3RjVP9SS0z/dGNU/5eQcv+qqZr/dGNU/5eQcv+XkHL/dGNU/6qpmv+XkHL/l5By/6qpmv+qqZr/l5By/5eQcv+XkHL/l5By/3RjVP9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv+XkHL/l5By/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv7+4/7+/uP+/v7j/v7+4/6qpmv+XkHL/l5By/zsgHP8hExP/IRMT/1JLTP9SS0z/dGNU/5eQcv+XkHL/qqma/1JLTP9SS0z/UktM/3RjVP+XkHL/OyAc/1QxKP9wTTr/jGVJ/3BNOv+qqZr/l5By/3RjVP9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv+qqZr/qqma/5eQcv90Y1T/UktM/3RjVP+XkHL/l5By/3RjVP90Y1T/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/3RjVP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqpmv+/v7j/v7+4/6qpmv+XkHL/dGNU/1JLTP8hExP/IRMT/yETE/9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv90Y1T/UktM/1JLTP9SS0z/dGNU/6qpmv9UMSj/cE06/3BNOv9UMSj/qqma/3RjVP9SS0z/UktM/1JLTP90Y1T/l5By/6qpmv+qqZr/v7+4/7+/uP+qqZr/qqma/5eQcv+XkHL/qqma/6qpmv+XkHL/l5By/5eQcv+XkHL/dGNU/1JLTP9SS0z/UktM/1JLTP90Y1T/l5By/5eQcv+XkHL/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqqZr/qqma/6qpmv+qqZr/qqma/5eQcv+XkHL/OyAc/yETE/8hExP/UktM/1JLTP90Y1T/l5By/5eQcv+qqZr/l5By/3RjVP9SS0z/dGNU/5eQcv+qqZr/VDEo/3BNOv9wTTr/OyAc/6qpmv+XkHL/dGNU/1JLTP90Y1T/l5By/6qpmv+/v7j/v7+4/7+/uP+/v7j/v7+4/7+/uP+qqZr/qqma/7+/uP+/v7j/qqma/6qpmv+qqZr/l5By/3RjVP9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv+qqZr/qqma/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl5By/6qpmv+qqZr/l5By/6qpmv+qqZr/l5By/zsgHP8hExP/IRMT/1JLTP9SS0z/dGNU/5eQcv+qqZr/qqma/3RjVP90Y1T/UktM/3RjVP+XkHL/qqma/zsgHP9wTTr/VDEo/zsgHP+qqZr/l5By/3RjVP9SS0z/UktM/3RjVP90Y1T/l5By/6qpmv+/v7j/v7+4/6qpmv+XkHL/dGNU/7+/uP+/v7j/v7+4/7+/uP+/v7j/qqma/5eQcv9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP+XkHL/qqma/7+/uP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeQcv+XkHL/l5By/5eQcv+XkHL/dGNU/1QxKP87IBz/IRMT/yETE/9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv90Y1T/dGNU/1JLTP90Y1T/dGNU/6qpmv87IBz/VDEo/3BNOv+qqZr/qqma/3RjVP9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv+qqZr/v7+4/7+/uP+qqZr/l5By/3RjVP+qqZr/v7+4/7+/uP+qqZr/qqma/5eQcv90Y1T/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv+qqZr/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABKc0f/X4pR/1+KUf9Kc0f/SnNH/0BfQ/9AX0P/O0s+/ztLPv87Sz7/O0s+/ztLPv87Sz7/QF9D/0pzR/9Kc0f/dGNU/3RjVP9SS0z/dGNU/3RjVP+XkHL/qqma/3BNOv9UMSj/qqma/5eQcv90Y1T/UktM/1JLTP9SS0z/UktM/1JLTP+XkHL/qqma/6qpmv+qqZr/qqma/5eQcv9SS0z/X4pR/1+KUf9filH/X4pR/1+KUf9Kc0f/SnNH/0BfQ/87Sz7/O0s+/ztLPv87Sz7/QF9D/0pzR/9Kc0f/X4pR/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX4pR/1+KUf97n2T/X4pR/1+KUf9filH/SnNH/ztLPv87Sz7/O0s+/ztLPv87Sz7/O0s+/0pzR/9filH/X4pR/3RjVP90Y1T/UktM/3RjVP9SS0z/l5By/5eQcv9wTTr/OyAc/5eQcv+XkHL/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/dGNU/5eQcv+XkHL/l5By/5eQcv90Y1T/UktM/0pzR/9filH/SnNH/1+KUf9Kc0f/QF9D/ztLPv9Kc0f/QF9D/ztLPv87Sz7/QF9D/0pzR/87Sz7/QF9D/0pzR/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF+KUf9filH/X4pR/0pzR/+/v7j/QF9D/7+/uP87Sz7/O0s+/ztLPv87Sz7/O0s+/ztLPv9AX0P/QF9D/0pzR/90Y1T/dGNU/1JLTP90Y1T/UktM/1JLTP90Y1T/VDEo/zsgHP90Y1T/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/UktM/1JLTP9SS0z/dGNU/3RjVP9SS0z/UktM/1JLTP9AX0P/SnNH/0BfQ/9Kc0f/SnNH/0pzR/9AX0P/SnNH/0BfQ/87Sz7/O0s+/0BfQ/9Kc0f/QF9D/0pzR/9Kc0f/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
                    //	"SkinId": "Standard_Custom",
                    //	"UIProfile": 0
                    //}

                    try
                    {
                        _playerInfo.ClientId         = payload.ClientRandomId;
                        _playerInfo.CurrentInputMode = payload.CurrentInputMode;
                        _playerInfo.DefaultInputMode = payload.DefaultInputMode;
                        _playerInfo.DeviceModel      = payload.DeviceModel;
                        _playerInfo.DeviceOS         = payload.DeviceOS;
                        _playerInfo.GameVersion      = payload.GameVersion;
                        _playerInfo.GuiScale         = payload.GuiScale;
                        _playerInfo.LanguageCode     = payload.LanguageCode;
                        _playerInfo.ServerAddress    = payload.ServerAddress;
                        _playerInfo.UIProfile        = payload.UIProfile;

                        _playerInfo.Skin = new Skin()
                        {
                            SkinType     = payload.SkinId,
                            Texture      = Convert.FromBase64String((string)payload.SkinData),
                            GeometryType = (string)payload.SkinGeometryName,
                            GeometryData = Encoding.ASCII.GetString(Convert.FromBase64String((string)payload.SkinGeometryData))
                        };
                    }
                    catch (Exception e)
                    {
                        Log.Error("Skin info", e);
                    }
                }

                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("Input JSON string: " + certificateChain);
                    }

                    dynamic json = JObject.Parse(certificateChain);

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"JSON:\n{json}");
                    }

                    string validationKey     = null;
                    JArray chain             = json.chain;
                    var    chainArray        = chain.ToArray();
                    string identityPublicKey = null;
                    foreach (dynamic o in chainArray)
                    {
                        IDictionary <string, dynamic> headers = JWT.Headers(o.ToString());

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug("Raw chain element:\n" + o.ToString());
                            Log.Debug($"JWT Header: {string.Join(";", headers)}");

                            dynamic jsonPayload = JObject.Parse(JWT.Payload(o.ToString()));
                            Log.Debug($"JWT Payload:\n{jsonPayload}");
                        }

                        // x5u cert (string): MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V
                        if (headers.ContainsKey("x5u"))
                        {
                            string certString = headers["x5u"];
                            if (identityPublicKey == null && CertificateData.MojangRootKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                            {
                                Log.Debug("Key is ok, and got Mojang root");
                            }
                            else if (identityPublicKey == null)
                            {
                                if (chainArray.Length > 1)
                                {
                                    Log.Debug("Got client cert (client root)");
                                    continue;
                                }
                                else if (chainArray.Length == 1)
                                {
                                    Log.Debug("Selfsigned chain");
                                }
                            }
                            else if (identityPublicKey.Equals(certString))
                            {
                                Log.Debug("Derived Key is ok");
                            }

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"x5u cert (string): {certString}");
                                ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(certString);
                                Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                            }

                            // Validate
                            var             newKey = CryptoUtils.ImportECDsaCngKeyFromString(certString);
                            CertificateData data   = JWT.Decode <CertificateData>(o.ToString(), newKey);
                            if (data != null)
                            {
                                identityPublicKey = data.IdentityPublicKey;

                                if (Log.IsDebugEnabled)
                                {
                                    Log.Debug("Decoded token success");
                                }

                                if (CertificateData.MojangRootKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    Log.Debug("Got Mojang key. Is valid = " + data.CertificateAuthority);
                                    validationKey = data.IdentityPublicKey;
                                }
                                else if (validationKey != null && validationKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    _playerInfo.CertificateData = data;
                                }
                                else
                                {
                                    if (data.ExtraData == null)
                                    {
                                        continue;
                                    }

                                    // Self signed, make sure they don't fake XUID
                                    if (data.ExtraData.Xuid != null)
                                    {
                                        Log.Warn("Received fake XUID from " + data.ExtraData.DisplayName);
                                        data.ExtraData.Xuid = null;
                                    }

                                    _playerInfo.CertificateData = data;
                                }
                            }
                            else
                            {
                                Log.Error("Not a valid Identity Public Key for decoding");
                            }
                        }
                    }

                    //TODO: Implement disconnect here

                    {
                        _playerInfo.Username = _playerInfo.CertificateData.ExtraData.DisplayName;
                        _session.Username    = _playerInfo.Username;
                        string identity = _playerInfo.CertificateData.ExtraData.Identity;

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug($"Connecting user {_playerInfo.Username} with identity={identity}");
                        }
                        _playerInfo.ClientUuid = new UUID(identity);

                        _session.CryptoContext = new CryptoContext
                        {
                            UseEncryption = Config.GetProperty("UseEncryptionForAll", false) || (Config.GetProperty("UseEncryption", true) && !string.IsNullOrWhiteSpace(_playerInfo.CertificateData.ExtraData.Xuid)),
                        };

                        if (_session.CryptoContext.UseEncryption)
                        {
                            ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(_playerInfo.CertificateData.IdentityPublicKey);
                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                            }

                            // Create shared shared secret
                            ECDiffieHellmanCng ecKey = new ECDiffieHellmanCng(384);
                            ecKey.HashAlgorithm         = CngAlgorithm.Sha256;
                            ecKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                            ecKey.SecretPrepend         = Encoding.UTF8.GetBytes("RANDOM SECRET");                     // Server token

                            byte[] secret = ecKey.DeriveKeyMaterial(publicKey);

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"SECRET KEY (b64):\n{Convert.ToBase64String(secret)}");
                            }

                            {
                                RijndaelManaged rijAlg = new RijndaelManaged
                                {
                                    BlockSize    = 128,
                                    Padding      = PaddingMode.None,
                                    Mode         = CipherMode.CFB,
                                    FeedbackSize = 8,
                                    Key          = secret,
                                    IV           = secret.Take(16).ToArray(),
                                };

                                // Create a decrytor to perform the stream transform.
                                ICryptoTransform decryptor      = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream     inputStream    = new MemoryStream();
                                CryptoStream     cryptoStreamIn = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read);

                                ICryptoTransform encryptor       = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream     outputStream    = new MemoryStream();
                                CryptoStream     cryptoStreamOut = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);

                                _session.CryptoContext.Algorithm       = rijAlg;
                                _session.CryptoContext.Decryptor       = decryptor;
                                _session.CryptoContext.Encryptor       = encryptor;
                                _session.CryptoContext.InputStream     = inputStream;
                                _session.CryptoContext.OutputStream    = outputStream;
                                _session.CryptoContext.CryptoStreamIn  = cryptoStreamIn;
                                _session.CryptoContext.CryptoStreamOut = cryptoStreamOut;
                            }

                            var response = McpeServerToClientHandshake.CreateObject();
                            response.NoBatch    = true;
                            response.ForceClear = true;

                            string b64Key = Convert.ToBase64String(ecKey.PublicKey.GetDerEncoded());

                            var j = CngKey.Create(CngAlgorithm.ECDiffieHellmanP384, null, new CngKeyCreationParameters()
                            {
                                ExportPolicy = CngExportPolicies.AllowPlaintextExport, KeyUsage = CngKeyUsages.AllUsages
                            });
                            var jwt = JWT.Encode(new object[] {
                                new [] { "salt", "sNUMIRcN2BSNRw93P5vGpg==" }
                            }, j, JwsAlgorithm.ES384, new Dictionary <string, object> {
                                { "x5u", b64Key }
                            });
                            response.token = jwt;

                            _session.SendPackage(response);

                            if (Log.IsDebugEnabled)
                            {
                                Log.Warn($"Encryption enabled for {_session.Username}");
                            }
                        }
                    }
                }

                if (!_session.CryptoContext.UseEncryption)
                {
                    _session.MessageHandler.HandleMcpeClientToServerHandshake(null);
                }
            }
            catch (Exception e)
            {
                Log.Error("Decrypt", e);
            }
        }
コード例 #22
0
ファイル: Kits.cs プロジェクト: FuryTacticz/Plugins
        public Package McpeLogin(McpeLogin packet, Player player)
        {
            if (PlayersKitActivated.Contains(player.Username))
            {
                PlayersKitActivated.Remove(player.Username);
            }

            player.SendMessage(string.Format(ChatColors.Yellow + "Welcome " + player.Username), type: MessageType.Chat);

            player.AddPopup(new Popup()
            {
                Message = $"{ChatColors.Gold}Fury Is Godly At C# ~ USER: " + player.Username,
                Duration = 99999999,
                Priority = 1000
            });

            return packet;
        }
コード例 #23
0
ファイル: Player.cs プロジェクト: yungtechboy1/MiNET
        /// <summary>
        ///     Handles the login.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <exception cref="System.Exception">
        ///     No username on login
        ///     or
        ///     No username on login
        /// </exception>
        protected virtual void HandleLogin(McpeLogin message)
        {
            if (Username != null) return; // Already doing login

            if (!Regex.IsMatch(message.username, "^[A-Za-z0-9_-]{3,16}$"))
            {
                SendPackage(new McpeDisconnect() {message = "Invalid username."});
                return;
            }

            Username = message.username;
            ClientId = message.clientId;

            Session = Server.SessionManager.CreateSession(this);
            if (Server.IsSecurityEnabled)
            {
                User = Server.UserManager.FindByName(Username);
            }

            Skin = message.skin;
            //Skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192)) };

            Log.WarnFormat("Login attempt by: {0}", Username);

            if (Username.Trim().Length == 0)
            {
                SendPackage(new McpePlayerStatus {status = 2});
                return;
            }

            // Check if the user already exist, that case bumpt the old one
            Level.RemoveDuplicatePlayers(Username);

            if (Username.StartsWith("Player")) IsBot = true; // HACK
            //if (!Username.StartsWith("gurun")) return; // HACK

            if (Username.StartsWith("Wix")
                || EndPoint.Address.ToString().EndsWith("166.91")
                || (Username.StartsWith("Wiz"))
                || (Username.StartsWith("Anon"))
                || (Username.StartsWith("Gang"))
                || (Username.StartsWith("Pafty"))
                || (Username.StartsWith("tanker"))
                || (Username.StartsWith("Chubet"))
                || (Username.StartsWith("Anth"))
                || (Username.StartsWith("10de"))
                )
            {
                SendPackage(new McpeDisconnect() {message = "From [gurun]: You've been temp banned.\nPlease try again later :-)"});
                return;
            }

            // Start game

            Level.EntityManager.AddEntity(null, this);

            // We send a ping here to get an initial value for chunk-sending
            _pingSendTime = DateTime.UtcNow.Ticks/TimeSpan.TicksPerMillisecond;
            SendPackage(new ConnectedPing {sendpingtime = _pingSendTime});

            SendPackage(new McpePlayerStatus {status = 0});
            SendStartGame();
            SendSetSpawnPosition();
            SendSetTime();
            SendPackage(new McpeSetDifficulty {difficulty = (int) Level.Difficulty});
            SendPackage(new McpeAdventureSettings {flags = Level.IsSurvival ? 0x20 : 0x80});
            //SendPackage(new McpeAdventureSettings { flags = Level.IsSurvival ? 0x80 : 0x80 });
            SendSetHealth();

            SendPackage(new McpeSetEntityData
            {
                entityId = EntityId,
                metadata = GetMetadata()
            });

            Level.AddPlayer(this, string.Format("{0} joined the game!", Username));

            SendPackage(new McpeContainerSetContent
            {
                windowId = 0,
                slotData = Inventory.Slots,
                hotbarData = Inventory.ItemHotbar
            });

            SendPackage(new McpeContainerSetContent
            {
                windowId = 0x78, // Armor windows ID
                slotData = Inventory.Armor,
                hotbarData = null
            });

            //SendPackage(new McpePlayerStatus {status = 3});

            SendChunksForKnownPosition();

            //IsSpawned = true;

            LastUpdatedTime = DateTime.UtcNow;

            if (IsBot)
            {
                InitializePlayer();
                return;
            }
        }
コード例 #24
0
ファイル: BedrockClient.cs プロジェクト: wqd1019dqw/Alex
        private void SendAlexLogin(string username)
        {
            JWT.JsonMapper = new NewtonsoftMapper();

            var clientKey = XblmsaService.MinecraftKeyPair;// CryptoUtils.GenerateClientKey();

            ECDsa signKey = ConvertToSingKeyFormat(clientKey);

            string b64Key = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(clientKey.Public).GetEncoded().EncodeBase64();

            string identity, xuid = "";

            byte[] certChain = null;

            if (XblmsaService.MinecraftChain != null)
            {
                var element = XblmsaService.DecodedChain.Chain[1];

                Username = username = element.ExtraData.DisplayName;
                identity = element.ExtraData.Identity;
                xuid     = element.ExtraData.Xuid;

                certChain = XblmsaService.MinecraftChain;
                Log.Info($"Using signed certificate chain");
            }
            else
            {
                long iat = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                long exp = DateTimeOffset.UtcNow.AddDays(1).ToUnixTimeSeconds();

                //ECDsa signKey = ConvertToSingKeyFormat(newKey);

                CertificateData certificateData = new CertificateData
                {
                    Exp       = exp,
                    Iat       = iat,
                    ExtraData = new ExtraData
                    {
                        DisplayName = username,
                        Identity    = Guid.NewGuid().ToString(),
                        XUID        = ""
                    },
                    Iss = "self",
                    IdentityPublicKey    = b64Key,
                    CertificateAuthority = true,
                    Nbf         = iat,
                    RandomNonce = new Random().Next(),
                };

                certChain = EncodeJwt(certificateData, b64Key, signKey);
            }

            var skinData = EncodeSkinJwt(clientKey, signKey, username, b64Key);

            byte[] data = CryptoUtils.CompressJwtBytes(certChain, skinData, CompressionLevel.Fastest);

            McpeLogin loginPacket = new McpeLogin
            {
                protocolVersion = McpeProtocolInfo.ProtocolVersion,
                payload         = data
            };

            Session.CryptoContext = new CryptoContext()
            {
                ClientKey     = clientKey,
                UseEncryption = false,
            };

            SendPacket(loginPacket);

            //    Session.CryptoContext.UseEncryption = true;
        }
コード例 #25
0
 public void HandleMcpeLogin(McpeLogin message)
 {
     WritePackage(message);
 }
コード例 #26
0
        protected void DecodeCert(McpeLogin message)
        {
            _playerInfo = new PlayerInfo();

            // Get bytes
            byte[] buffer = message.payload;

            if (message.payloadLenght != buffer.Length) throw new Exception($"Wrong lenght {message.payloadLenght} != {message.payload.Length}");
            // Decompress bytes

            Log.Debug("Lenght: " + message.payloadLenght + ", Message: " + Convert.ToBase64String(buffer));

            MemoryStream stream = new MemoryStream(buffer);
            if (stream.ReadByte() != 0x78)
            {
                throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C");
            }
            stream.ReadByte();

            string certificateChain;
            string skinData;

            using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false))
            {
                // Get actual package out of bytes
                MemoryStream destination = MiNetServer.MemoryStreamManager.GetStream();
                defStream2.CopyTo(destination);
                destination.Position = 0;
                NbtBinaryReader reader = new NbtBinaryReader(destination, false);

                try
                {
                    var countCertData = reader.ReadInt32();
                    Log.Debug("Count cert: " + countCertData);
                    certificateChain = Encoding.UTF8.GetString(reader.ReadBytes(countCertData));
                    Log.Debug("Decompressed certificateChain " + certificateChain);

                    var countSkinData = reader.ReadInt32();
                    Log.Debug("Count skin: " + countSkinData);
                    skinData = Encoding.UTF8.GetString(reader.ReadBytes(countSkinData));
                    Log.Debug("Decompressed skinData" + skinData);
                }
                catch (Exception e)
                {
                    Log.Error("Parsing login", e);
                    return;
                }
            }

            try
            {
                {
                    if (Log.IsDebugEnabled) Log.Debug("Input JSON string: " + certificateChain);

                    dynamic json = JObject.Parse(certificateChain);

                    if (Log.IsDebugEnabled) Log.Debug($"JSON:\n{json}");

                    string validationKey = null;
                    foreach (dynamic o in json.chain)
                    {
                        IDictionary<string, dynamic> headers = JWT.Headers(o.ToString());

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug("Raw chain element:\n" + o.ToString());
                            Log.Debug($"JWT Header: {string.Join(";", headers)}");

                            dynamic jsonPayload = JObject.Parse(JWT.Payload(o.ToString()));
                            Log.Debug($"JWT Payload:\n{jsonPayload}");
                        }

                        // x5u cert (string): MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V
                        if (headers.ContainsKey("x5u"))
                        {
                            string certString = headers["x5u"];

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"x5u cert (string): {certString}");
                                ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(certString);
                                Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                            }

                            // Validate
                            CngKey newKey = CryptoUtils.ImportECDsaCngKeyFromString(certString);
                            CertificateData data = JWT.Decode<CertificateData>(o.ToString(), newKey);

                            if (data != null)
                            {
                                if (Log.IsDebugEnabled) Log.Debug("Decoded token success");

                                if (CertificateData.MojangRootKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    Log.Debug("Got Mojang key. Is valid = " + data.CertificateAuthority);
                                    validationKey = data.IdentityPublicKey;
                                }
                                else if (validationKey != null && validationKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    _playerInfo.CertificateData = data;
                                }
                                else
                                {
                                    // Self signed, make sure they don't fake XUID
                                    if (data.ExtraData.Xuid != null)
                                    {
                                        Log.Warn("Received fake XUID from " + data.ExtraData.DisplayName);
                                        data.ExtraData.Xuid = null;
                                    }

                                    _playerInfo.CertificateData = data;
                                }
                            }
                            else
                            {
                                Log.Error("Not a valid Identity Public Key for decoding");
                            }
                        }
                    }

                    //TODO: Implement disconnect here

                    {
                        _playerInfo.Username = _playerInfo.CertificateData.ExtraData.DisplayName;
                        _session.Username = _playerInfo.Username;
                        string identity = _playerInfo.CertificateData.ExtraData.Identity;

                        if (Log.IsDebugEnabled) Log.Debug($"Connecting user {_playerInfo.Username} with identity={identity}");
                        _playerInfo.ClientUuid = new UUID(new Guid(identity));

                        _session.CryptoContext = new CryptoContext
                        {
                            UseEncryption = Config.GetProperty("UseEncryptionForAll", false) || (Config.GetProperty("UseEncryption", true) && !string.IsNullOrWhiteSpace(_playerInfo.CertificateData.ExtraData.Xuid)),
                        };

                        if (_session.CryptoContext.UseEncryption)
                        {
                            ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(_playerInfo.CertificateData.IdentityPublicKey);
                            if (Log.IsDebugEnabled) Log.Debug($"Cert:\n{publicKey.ToXmlString()}");

                            // Create shared shared secret
                            ECDiffieHellmanCng ecKey = new ECDiffieHellmanCng(384);
                            ecKey.HashAlgorithm = CngAlgorithm.Sha256;
                            ecKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                            ecKey.SecretPrepend = Encoding.UTF8.GetBytes("RANDOM SECRET"); // Server token

                            byte[] secret = ecKey.DeriveKeyMaterial(publicKey);

                            if (Log.IsDebugEnabled) Log.Debug($"SECRET KEY (b64):\n{Convert.ToBase64String(secret)}");

                            {
                                RijndaelManaged rijAlg = new RijndaelManaged
                                {
                                    BlockSize = 128,
                                    Padding = PaddingMode.None,
                                    Mode = CipherMode.CFB,
                                    FeedbackSize = 8,
                                    Key = secret,
                                    IV = secret.Take(16).ToArray(),
                                };

                                // Create a decrytor to perform the stream transform.
                                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream inputStream = new MemoryStream();
                                CryptoStream cryptoStreamIn = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read);

                                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream outputStream = new MemoryStream();
                                CryptoStream cryptoStreamOut = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);

                                _session.CryptoContext.Algorithm = rijAlg;
                                _session.CryptoContext.Decryptor = decryptor;
                                _session.CryptoContext.Encryptor = encryptor;
                                _session.CryptoContext.InputStream = inputStream;
                                _session.CryptoContext.OutputStream = outputStream;
                                _session.CryptoContext.CryptoStreamIn = cryptoStreamIn;
                                _session.CryptoContext.CryptoStreamOut = cryptoStreamOut;
                            }

                            var response = McpeServerExchange.CreateObject();
                            response.NoBatch = true;
                            response.ForceClear = true;
                            response.serverPublicKey = Convert.ToBase64String(ecKey.PublicKey.GetDerEncoded());
                            response.tokenLenght = (short) ecKey.SecretPrepend.Length;
                            response.token = ecKey.SecretPrepend;

                            _session.SendPackage(response);

                            if (Log.IsDebugEnabled) Log.Warn($"Encryption enabled for {_session.Username}");
                        }
                    }
                }

                {
                    if (Log.IsDebugEnabled) Log.Debug("Input SKIN string: " + skinData);

                    IDictionary<string, dynamic> headers = JWT.Headers(skinData);
                    dynamic payload = JObject.Parse(JWT.Payload(skinData));

                    if (Log.IsDebugEnabled) Log.Debug($"Skin JWT Header: {string.Join(";", headers)}");
                    if (Log.IsDebugEnabled) Log.Debug($"Skin JWT Payload:\n{payload.ToString()}");

                    // Skin JWT Payload:
                    //{
                    // "ClientRandomId": -1256727416,
                    // "ServerAddress": "yodamine.com:19132",
                    // "SkinData": "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Af/3/wH/9/8B//f/Af/3/wAAAP/yrmj/8q5o//KuaP/yrmj/8q5o//KuaP/yrmj/8q5o/wMCAv8B//f/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD//wAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgD/AQEB/wEBAf8BAQH//fn2//359v/9+fb//fn2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUF/wkICP8JCQn/EhIS//KuaP/yrmj/AAAA/wkJCf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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",
                    // "SkinId": "Standard_Custom"
                    //}

                    _playerInfo.ServerAddress = payload.ServerAddress;
                    _playerInfo.ClientId = payload.ClientRandomId;

                    _playerInfo.Skin = new Skin()
                    {
                        SkinType = payload.SkinId,
                        Texture = Convert.FromBase64String((string) payload.SkinData),
                    };
                }

                if (!_session.CryptoContext.UseEncryption)
                {
                    _session.MessageHandler.HandleMcpeClientMagic(null);
                }
            }
            catch (Exception e)
            {
                Log.Error("Decrypt", e);
            }
        }
コード例 #27
0
ファイル: NiceLobbyPlugin.cs プロジェクト: venomshock/MiNET
 public Package LoginHandler(McpeLogin packet, Player player)
 {
     player.DisplayName = TextUtils.Center($"{GetNameTag(packet.username ?? "")}");
     return(packet);
 }
コード例 #28
0
        protected void DecodeCertMono(McpeLogin message)
        {
            byte[] buffer = message.payload;

            if (message.payload.Length != buffer.Length)
            {
                Log.Debug($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
                throw new Exception($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
            }

            if (Log.IsDebugEnabled)
            {
                Log.Debug("Lenght: " + message.payload.Length + ", Message: " + buffer.EncodeBase64());
            }

            string certificateChain;
            string skinData;

            try
            {
                var destination = new MemoryStream(buffer);
                destination.Position = 0;
                NbtBinaryReader reader = new NbtBinaryReader(destination, false);

                var countCertData = reader.ReadInt32();
                certificateChain = Encoding.UTF8.GetString(reader.ReadBytes(countCertData));
                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Certificate Chain (Lenght={countCertData})\n{certificateChain}");
                }

                var countSkinData = reader.ReadInt32();
                skinData = Encoding.UTF8.GetString(reader.ReadBytes(countSkinData));
                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Skin data (Lenght={countSkinData})\n{skinData}");
                }
            }
            catch (Exception e)
            {
                Log.Error("Parsing login", e);
                return;
            }

            try
            {
                {
                    IDictionary <string, dynamic> headers = JWT.Headers(skinData);
                    dynamic payload = JObject.Parse(JWT.Payload(skinData));

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Header: {string.Join(";", headers)}");
                    }
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Payload:\n{payload.ToString()}");
                    }

                    try
                    {
                        _playerInfo.ClientId         = payload.ClientRandomId;
                        _playerInfo.CurrentInputMode = payload.CurrentInputMode;
                        _playerInfo.DefaultInputMode = payload.DefaultInputMode;
                        _playerInfo.DeviceModel      = payload.DeviceModel;
                        _playerInfo.DeviceOS         = payload.DeviceOS;
                        _playerInfo.GameVersion      = payload.GameVersion;
                        _playerInfo.GuiScale         = payload.GuiScale;
                        _playerInfo.LanguageCode     = payload.LanguageCode;
                        _playerInfo.ServerAddress    = payload.ServerAddress;
                        _playerInfo.UIProfile        = payload.UIProfile;

                        _playerInfo.Skin = new Skin()
                        {
                            CapeData         = Convert.FromBase64String((string)payload.CapeData),
                            SkinId           = payload.SkinId,
                            SkinData         = Convert.FromBase64String((string)payload.SkinData),
                            SkinGeometryName = payload.SkinGeometryName,
                            SkinGeometry     = Encoding.UTF8.GetString(Convert.FromBase64String((string)payload.SkinGeometry)),
                        };
                        Log.Warn($"Cape data lenght={_playerInfo.Skin.CapeData.Length}");
                    }
                    catch (Exception e)
                    {
                        Log.Error("Parsing skin data", e);
                    }
                }

                //var chainArray = chain.ToArray();

                string validationKey     = null;
                string identityPublicKey = null;
                //if (!isMono)
                {
                    dynamic json = JObject.Parse(certificateChain);

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Certificate JSON:\n{json}");
                    }

                    JArray chain = json.chain;

                    foreach (JToken token in chain)
                    {
                        IDictionary <string, dynamic> headers = JWT.Headers(token.ToString());

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug("Raw chain element:\n" + token.ToString());
                            Log.Debug($"JWT Header: {string.Join(";", headers)}");

                            dynamic jsonPayload = JObject.Parse(JWT.Payload(token.ToString()));
                            Log.Debug($"JWT Payload:\n{jsonPayload}");
                        }

                        // Mojang root x5u cert (string): MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V

                        if (!headers.ContainsKey("x5u"))
                        {
                            continue;
                        }

                        string x5u = headers["x5u"];

                        if (identityPublicKey == null)
                        {
                            if (CertificateData.MojangRootKey.Equals(x5u, StringComparison.InvariantCultureIgnoreCase))
                            {
                                Log.Debug("Key is ok, and got Mojang root");
                            }
                            else if (chain.Count > 1)
                            {
                                Log.Debug("Got client cert (client root)");
                                continue;
                            }
                            else if (chain.Count == 1)
                            {
                                Log.Debug("Selfsigned chain");
                            }
                        }
                        else if (identityPublicKey.Equals(x5u))
                        {
                            Log.Debug("Derived Key is ok");
                        }
                        // Validate

                        var key = PublicKeyFactory.CreateKey(x5u.DecodeBase64Url());

                        CertificateData data = CryptoUtils.Decode(token.ToString(), key);
                        if (data != null)
                        {
                            identityPublicKey = data.IdentityPublicKey;

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug("Decoded token success");
                            }

                            if (CertificateData.MojangRootKey.Equals(x5u, StringComparison.InvariantCultureIgnoreCase))
                            {
                                Log.Debug("Got Mojang key. Is valid = " + data.CertificateAuthority);
                                validationKey = data.IdentityPublicKey;
                            }
                            else if (validationKey != null && validationKey.Equals(x5u, StringComparison.InvariantCultureIgnoreCase))
                            {
                                _playerInfo.CertificateData = data;
                            }
                            else
                            {
                                if (data.ExtraData == null)
                                {
                                    continue;
                                }

                                // Self signed, make sure they don't fake XUID
                                if (data.ExtraData.Xuid != null)
                                {
                                    Log.Warn("Received fake XUID from " + data.ExtraData.DisplayName);
                                    data.ExtraData.Xuid = null;
                                }

                                _playerInfo.CertificateData = data;
                            }
                        }
                        else
                        {
                            Log.Error("Not a valid Identity Public Key for decoding");
                        }
                    }
                }

                //TODO: Implement disconnect here


                _playerInfo.Username = _playerInfo.CertificateData.ExtraData.DisplayName;
                _session.Username    = _playerInfo.Username;
                string identity = _playerInfo.CertificateData.ExtraData.Identity;

                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Connecting user {_playerInfo.Username} with identity={identity}");
                }
                _playerInfo.ClientUuid = new UUID(identity);

                bool useEncryption = (Config.GetProperty("UseEncryptionForAll", false) ||
                                      (Config.GetProperty("UseEncryption", true) &&
                                       !string.IsNullOrWhiteSpace(_playerInfo.CertificateData.ExtraData.Xuid)));

                if (useEncryption)
                {
                    var publicKey = PublicKeyFactory.CreateKey(_playerInfo.CertificateData.IdentityPublicKey.DecodeBase64Url());

                    string                    namedCurve = "secp384r1";
                    ECKeyPairGenerator        pGen       = new ECKeyPairGenerator();
                    ECKeyGenerationParameters genParam   = new ECKeyGenerationParameters(
                        SecNamedCurves.GetOid(namedCurve),
                        new SecureRandom());
                    pGen.Init(genParam);

                    AsymmetricCipherKeyPair keyPair = pGen.GenerateKeyPair();

                    ECDHBasicAgreement agreement = new ECDHBasicAgreement();
                    agreement.Init(keyPair.Private);

                    byte[] preHash = agreement.CalculateAgreement(publicKey).ToByteArray();

                    byte[] prepend = Encoding.UTF8.GetBytes("RANDOM SECRET");
                    byte[] secret;

                    SHA256Managed sha = new SHA256Managed();
                    using (var memoryStream = new MemoryStream())
                    {
                        memoryStream.Write(prepend, 0, prepend.Length);
                        memoryStream.Write(preHash, 0, preHash.Length);
                        memoryStream.Position = 0;
                        secret = sha.ComputeHash(memoryStream);
                    }
                    sha.Dispose();

                    //if (Log.IsDebugEnabled) Log.Debug($"SECRET KEY (b64, {secret.Length}):\n{secret.EncodeBase64()}");

                    {
                        RijndaelManaged rijAlg = new RijndaelManaged
                        {
                            BlockSize    = 128,
                            Padding      = PaddingMode.None,
                            Mode         = CipherMode.CFB,
                            FeedbackSize = 8,
                            Key          = secret,
                            IV           = secret.Take(16).ToArray(),
                        };

                        // Create a decrytor to perform the stream transform.
                        ICryptoTransform decryptor      = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                        MemoryStream     inputStream    = new MemoryStream();
                        CryptoStream     cryptoStreamIn = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read);

                        ICryptoTransform encryptor       = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                        MemoryStream     outputStream    = new MemoryStream();
                        CryptoStream     cryptoStreamOut = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);

                        _session.CryptoContext = new CryptoContext
                        {
                            UseEncryption   = true,
                            Algorithm       = rijAlg,
                            Decryptor       = decryptor,
                            Encryptor       = encryptor,
                            InputStream     = inputStream,
                            OutputStream    = outputStream,
                            CryptoStreamIn  = cryptoStreamIn,
                            CryptoStreamOut = cryptoStreamOut
                        };


                        var pubKey1 = ((ECPublicKeyParameters)keyPair.Public);

                        byte[] asn = new byte[24]
                        {
                            0x30, 0x76, 0x30, 0x10, 0x6, 0x7, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x2,
                            0x1, 0x6, 0x5, 0x2b, 0x81, 0x4, 0x0, 0x22, 0x3, 0x62, 0x0, 0x4
                        };
                        string b64Key        = asn.Concat(ConvertToNCryptEccPublicBlob(pubKey1.Q).Skip(8)).ToArray().EncodeBase64();
                        var    handshakeJson = new HandshakeData()
                        {
                            salt = prepend.EncodeBase64()
                        };

                        string val = CryptoUtils.Encode(handshakeJson, keyPair.Private, JwsAlgorithm.ES384,
                                                        new Dictionary <string, object> {
                            { "x5u", b64Key }
                        });

                        var response = McpeServerToClientHandshake.CreateObject();
                        response.NoBatch    = true;
                        response.ForceClear = true;
                        response.token      = val;

                        _session.SendPackage(response);

                        if (Log.IsDebugEnabled)
                        {
                            Log.Warn($"Encryption enabled for {_session.Username}");
                        }
                    }
                }
                else
                {
                    _session.CryptoContext = new CryptoContext
                    {
                        UseEncryption = false
                    };

                    _session.MessageHandler.HandleMcpeClientToServerHandshake(null);
                }
            }
            catch (Exception e)
            {
                Log.Error("Decrypt", e);
            }
        }
コード例 #29
0
ファイル: LoginMessageHandler.cs プロジェクト: Polo1K/MiNET
        protected void DecodeCert(McpeLogin message)
        {
            _playerInfo = new PlayerInfo();

            // Get bytes
            byte[] buffer = message.payload;

            //Log.Debug($"Unknown byte in login packet is: {message.unknown}");

            if (message.payload.Length != buffer.Length)
            {
                Log.Debug($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
                throw new Exception($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
            }
            // Decompress bytes

            Log.Debug("Lenght: " + message.payload.Length + ", Message: " + Convert.ToBase64String(buffer));

            //MemoryStream stream = new MemoryStream(buffer);
            //if (stream.ReadByte() != 0x78)
            //{
            //	throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C");
            //}
            //stream.ReadByte();

            string certificateChain;
            string skinData;

            //using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false))
            {
                // Get actual package out of bytes
                //using (MemoryStream destination = MiNetServer.MemoryStreamManager.GetStream())
                {
                    //defStream2.CopyTo(destination);

                    var destination = new MemoryStream(buffer);
                    destination.Position = 0;
                    NbtBinaryReader reader = new NbtBinaryReader(destination, false);

                    try
                    {
                        var countCertData = reader.ReadInt32();
                        Log.Debug("Count cert: " + countCertData);
                        certificateChain = Encoding.UTF8.GetString(reader.ReadBytes(countCertData));
                        Log.Debug("Decompressed certificateChain " + certificateChain);

                        var countSkinData = reader.ReadInt32();
                        Log.Debug("Count skin: " + countSkinData);
                        skinData = Encoding.UTF8.GetString(reader.ReadBytes(countSkinData));
                        Log.Debug("Decompressed skinData" + skinData);
                    }
                    catch (Exception e)
                    {
                        Log.Error("Parsing login", e);
                        return;
                    }
                }
            }

            try
            {
                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("Input SKIN string: " + skinData);
                    }

                    IDictionary <string, dynamic> headers = JWT.Headers(skinData);
                    dynamic payload = JObject.Parse(JWT.Payload(skinData));

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Header: {string.Join(";", headers)}");
                    }
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Payload:\n{payload.ToString()}");
                    }

                    // Skin JWT Payload:

                    //{
                    //  "ADRole": 2,
                    //	"ClientRandomId": 1423700530444426768,
                    //	"CurrentInputMode": 1,
                    //	"DefaultInputMode": 1,
                    //	"DeviceModel": "ASUSTeK COMPUTER INC. N550JK",
                    //	"DeviceOS": 7,
                    //	"GameVersion": "1.1.0",
                    //	"GuiScale": 0,
                    //	"LanguageCode": "en_US",
                    //	"ServerAddress": "192.168.0.3:19132",
                    //	"SkinData": "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",
                    //	"SkinId": "Standard_Custom",
                    //	"TenantId": "",
                    //	"UIProfile": 0
                    //}

                    try
                    {
                        _playerInfo.ADRole           = payload.ADRole;
                        _playerInfo.ClientId         = payload.ClientRandomId;
                        _playerInfo.CurrentInputMode = payload.CurrentInputMode;
                        _playerInfo.DefaultInputMode = payload.DefaultInputMode;
                        _playerInfo.DeviceModel      = payload.DeviceModel;
                        _playerInfo.DeviceOS         = payload.DeviceOS;
                        _playerInfo.GameVersion      = payload.GameVersion;
                        _playerInfo.GuiScale         = payload.GuiScale;
                        _playerInfo.LanguageCode     = payload.LanguageCode;
                        _playerInfo.ServerAddress    = payload.ServerAddress;
                        _playerInfo.UIProfile        = payload.UIProfile;

                        _playerInfo.Skin = new Skin()
                        {
                            SkinType = payload.SkinId,
                            Texture  = Convert.FromBase64String((string)payload.SkinData),
                        };
                    }
                    catch (Exception e)
                    {
                        Log.Error("Skin info", e);
                    }
                }

                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("Input JSON string: " + certificateChain);
                    }

                    dynamic json = JObject.Parse(certificateChain);

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"JSON:\n{json}");
                    }

                    string validationKey = null;

                    foreach (dynamic o in json.chain)
                    {
                        IDictionary <string, dynamic> headers = JWT.Headers(o.ToString());

                        dynamic jsonPayload = JObject.Parse(JWT.Payload(o.ToString()));

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug("Raw chain element:\n" + o.ToString());
                            Log.Debug($"JWT Header: {string.Join(";", headers)}");

                            Log.Debug($"JWT Payload:\n{jsonPayload}");
                        }

                        if (jsonPayload["extraData"] == null)
                        {
                            continue;
                        }

                        _playerInfo.Username = jsonPayload["extraData"]["displayName"];
                        _session.Username    = _playerInfo.Username;

                        string identity = jsonPayload["extraData"]["identity"];

                        _playerInfo.ClientUuid = new UUID(new Guid(identity).ToByteArray());

                        _session.CryptoContext = new CryptoContext
                        {
                            UseEncryption = false
                        };

                        if (jsonPayload["extraData"]["XUID"] != null)
                        {
                            _playerInfo.CertificateData = new CertificateData
                            {
                                ExtraData = new ExtraData
                                {
                                    Xuid = jsonPayload["extraData"]["XUID"]
                                }
                            };
                        }
                        else
                        {
                            _playerInfo.CertificateData = new CertificateData
                            {
                                ExtraData = new ExtraData
                                {
                                    Xuid = ""
                                }
                            };
                        }
                    }
                }

                if (!_session.CryptoContext.UseEncryption)
                {
                    _session.MessageHandler.HandleMcpeClientToServerHandshake(null);
                }
            }
            catch (Exception e)
            {
                Log.Error("Decrypt", e);
            }
        }
コード例 #30
0
ファイル: Player.cs プロジェクト: WilliamGao1/MiNET
        /// <summary>
        ///     Handles the login.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <exception cref="System.Exception">
        ///     No username on login
        ///     or
        ///     No username on login
        /// </exception>
        private void HandleLogin(McpeLogin message)
        {
            if (Username != null) return; // Already doing login

            Username = message.username;
            ClientId = message.clientId;
            Skin = message.skin;
            //Skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192)) };

            Log.WarnFormat("Login attempt by: {0}", Username);

            if (Username.Trim().Length == 0)
            {
                SendPackage(new McpePlayerStatus {status = 2});
                return;
            }

            //Success = 0;
            //FailedClientIsOld = 1;
            //FailedServerIsOld, FailedClientIsNew = 2;
            //FailedPlayerAuthentication = 3;

            //if (Server.UserManager != null)
            //{
            //	if (Username == null || Server.UserManager.FindByName(Username) == null)
            //	{
            //		//TODO: Must implement disconnect properly. This is not enough for the client to "get it".
            //		SendPackage(new McpeLoginStatus {status = 3});
            //		return;
            //	}
            //}

            // Check if the user already exist, that case bumpt the old one
            Level.RemoveDuplicatePlayers(Username);

            if (Username.StartsWith("Player")) IsBot = true;

            if (Username.StartsWith("Wix")) return;
            if (Username.StartsWith("Wiz")) return;

            //LoadFromFile();

            // Start game

            Level.EntityManager.AddEntity(null, this);

            //const LOGIN_SUCCESS = 0;
            //const LOGIN_FAILED_CLIENT = 1;
            //const LOGIN_FAILED_SERVER = 2;
            //const PLAYER_SPAWN = 3;

            _pingSendTime = DateTime.UtcNow.Ticks/TimeSpan.TicksPerMillisecond;

            SendPackage(new ConnectedPing {sendpingtime = _pingSendTime});

            SendPackage(new McpePlayerStatus {status = 0});
            SendStartGame();
            SendSetSpawnPosition();
            SendSetTime();
            SendPackage(new McpeSetDifficulty {difficulty = (int) Level.Difficulty});
            SendPackage(new McpeAdventureSettings {flags = Level.IsSurvival ? 0x20 : 0x80});
            //SendPackage(new McpeAdventureSettings { flags = Level.IsSurvival ? 0x80 : 0x80 });
            SendSetHealth();

            SendPackage(new McpeSetEntityData
            {
                entityId = EntityId,
                metadata = GetMetadata()
            });

            Level.AddPlayer(this, string.Format("{0} joined the game!", Username));

            SendPackage(new McpeContainerSetContent
            {
                windowId = 0,
                slotData = Inventory.Slots,
                hotbarData = Inventory.ItemHotbar
            });

            SendPackage(new McpeContainerSetContent
            {
                windowId = 0x78, // Armor windows ID
                slotData = Inventory.Armor,
                hotbarData = null
            });

            //SendPackage(new McpePlayerStatus {status = 3});

            SendChunksForKnownPosition();

            //IsSpawned = true;

            LastUpdatedTime = DateTime.UtcNow;
        }
コード例 #31
0
ファイル: MiNetClient.cs プロジェクト: WilliamGao1/MiNET
        public void SendLogin(string username)
        {
            Skin skin = new Skin {Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192))};
            var packet = new McpeLogin()
            {
                clientId = 12345,
                username = username,
                protocol = 27,
                skin = skin
            };

            McpeBatch batch = new McpeBatch();
            byte[] buffer = CompressBytes(packet.Encode());

            batch.payloadSize = buffer.Length;
            batch.payload = buffer;

            SendPackage(batch);
        }
コード例 #32
0
        /// <summary>
        ///     Handles the login.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <exception cref="System.Exception">
        ///     No username on login
        ///     or
        ///     No username on login
        /// </exception>
        protected virtual void HandleLogin(McpeLogin message)
        {
            if (Username != null)
            {
                return;                               // Already doing login
            }
            Username = message.username;
            ClientId = message.clientId;

            User user = Server.UserManager.FindByName(Username);

            if (user != null)
            {
                Session = Server.SessionManager.FindSession(EndPoint, ClientId, Username);
                if (Session != null)
                {
                    User = user;
                }
            }


            Skin = message.skin;
            //Skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192)) };

            Log.WarnFormat("Login attempt by: {0}", Username);

            if (Username.Trim().Length == 0)
            {
                SendPackage(new McpePlayerStatus {
                    status = 2
                });
                return;
            }

            // Check if the user already exist, that case bumpt the old one
            Level.RemoveDuplicatePlayers(Username);

            if (Username.StartsWith("Player"))
            {
                IsBot = true;                                            // HACK
            }
            if (Username.StartsWith("Wix"))
            {
                return;
            }
            if (Username.StartsWith("Wiz"))
            {
                return;
            }
            if (Username.StartsWith("Aga"))
            {
                return;
            }

            // Start game

            Level.EntityManager.AddEntity(null, this);

            // We send a ping here to get an initial value for chunk-sending
            _pingSendTime = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
            SendPackage(new ConnectedPing {
                sendpingtime = _pingSendTime
            });


            SendPackage(new McpePlayerStatus {
                status = 0
            });
            SendStartGame();
            SendSetSpawnPosition();
            SendSetTime();
            SendPackage(new McpeSetDifficulty {
                difficulty = (int)Level.Difficulty
            });
            SendPackage(new McpeAdventureSettings {
                flags = Level.IsSurvival ? 0x20 : 0x80
            });
            //SendPackage(new McpeAdventureSettings { flags = Level.IsSurvival ? 0x80 : 0x80 });
            SendSetHealth();

            SendPackage(new McpeSetEntityData
            {
                entityId = EntityId,
                metadata = GetMetadata()
            });

            Level.AddPlayer(this, string.Format("{0} joined the game!", Username));

            SendPackage(new McpeContainerSetContent
            {
                windowId   = 0,
                slotData   = Inventory.Slots,
                hotbarData = Inventory.ItemHotbar
            });

            SendPackage(new McpeContainerSetContent
            {
                windowId   = 0x78,               // Armor windows ID
                slotData   = Inventory.Armor,
                hotbarData = null
            });

            //SendPackage(new McpePlayerStatus {status = 3});


            SendChunksForKnownPosition();

            //IsSpawned = true;

            LastUpdatedTime = DateTime.UtcNow;
        }
コード例 #33
0
        /// <summary>
        ///     Handles the login.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <exception cref="System.Exception">
        ///     No username on login
        ///     or
        ///     No username on login
        /// </exception>
        private void HandleLogin(McpeLogin message)
        {
            if (Username != null)
            {
                return;                               // Already doing login
            }
            Username = message.username;
            ClientId = message.clientId;
            Skin     = message.skin;
            //Skin = new Skin { Slim = false, Texture = Encoding.Default.GetBytes(new string('Z', 8192)) };

            Log.WarnFormat("Login attempt by: {0}", Username);

            if (Username.Trim().Length == 0)
            {
                SendPackage(new McpePlayerStatus {
                    status = 2
                });
                return;
            }

            //Success = 0;
            //FailedClientIsOld = 1;
            //FailedServerIsOld, FailedClientIsNew = 2;
            //FailedPlayerAuthentication = 3;

            //if (Server.UserManager != null)
            //{
            //	if (Username == null || Server.UserManager.FindByName(Username) == null)
            //	{
            //		//TODO: Must implement disconnect properly. This is not enough for the client to "get it".
            //		SendPackage(new McpeLoginStatus {status = 3});
            //		return;
            //	}
            //}

            // Check if the user already exist, that case bumpt the old one
            Level.RemoveDuplicatePlayers(Username);

            if (Username.StartsWith("Player"))
            {
                IsBot = true;
            }

            if (Username.StartsWith("Wix"))
            {
                return;
            }
            if (Username.StartsWith("Wiz"))
            {
                return;
            }

            //LoadFromFile();

            // Start game

            Level.EntityManager.AddEntity(null, this);

            //const LOGIN_SUCCESS = 0;
            //const LOGIN_FAILED_CLIENT = 1;
            //const LOGIN_FAILED_SERVER = 2;
            //const PLAYER_SPAWN = 3;

            _pingSendTime = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

            SendPackage(new ConnectedPing {
                sendpingtime = _pingSendTime
            });


            SendPackage(new McpePlayerStatus {
                status = 0
            });
            SendStartGame();
            SendSetSpawnPosition();
            SendSetTime();
            SendPackage(new McpeSetDifficulty {
                difficulty = (int)Level.Difficulty
            });
            SendPackage(new McpeAdventureSettings {
                flags = Level.IsSurvival ? 0x20 : 0x80
            });
            //SendPackage(new McpeAdventureSettings { flags = Level.IsSurvival ? 0x80 : 0x80 });
            SendSetHealth();

            SendPackage(new McpeSetEntityData
            {
                entityId = EntityId,
                metadata = GetMetadata()
            });

            Level.AddPlayer(this, string.Format("{0} joined the game!", Username));

            SendPackage(new McpeContainerSetContent
            {
                windowId   = 0,
                slotData   = Inventory.Slots,
                hotbarData = Inventory.ItemHotbar
            });

            SendPackage(new McpeContainerSetContent
            {
                windowId   = 0x78,               // Armor windows ID
                slotData   = Inventory.Armor,
                hotbarData = null
            });

            //SendPackage(new McpePlayerStatus {status = 3});


            SendChunksForKnownPosition();

            //IsSpawned = true;

            LastUpdatedTime = DateTime.UtcNow;
        }
コード例 #34
0
        protected void DecodeCert(McpeLogin message)
        {
            _playerInfo = new PlayerInfo();

            // Get bytes
            byte[] buffer = message.payload;

            //Log.Debug($"Unknown byte in login packet is: {message.unknown}");

            if (message.payload.Length != buffer.Length)
            {
                Log.Debug($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
                throw new Exception($"Wrong lenght {message.payload.Length} != {message.payload.Length}");
            }
            // Decompress bytes

            Log.Debug("Lenght: " + message.payload.Length + ", Message: " + Convert.ToBase64String(buffer));

            //MemoryStream stream = new MemoryStream(buffer);
            //if (stream.ReadByte() != 0x78)
            //{
            //	throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C");
            //}
            //stream.ReadByte();

            string certificateChain;
            string skinData;

            //using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false))
            {
                // Get actual package out of bytes
                //using (MemoryStream destination = MiNetServer.MemoryStreamManager.GetStream())
                {
                    //defStream2.CopyTo(destination);

                    var destination = new MemoryStream(buffer);
                    destination.Position = 0;
                    NbtBinaryReader reader = new NbtBinaryReader(destination, false);

                    try
                    {
                        var countCertData = reader.ReadInt32();
                        Log.Debug("Count cert: " + countCertData);
                        certificateChain = Encoding.UTF8.GetString(reader.ReadBytes(countCertData));
                        Log.Debug("Decompressed certificateChain " + certificateChain);

                        var countSkinData = reader.ReadInt32();
                        Log.Debug("Count skin: " + countSkinData);
                        skinData = Encoding.UTF8.GetString(reader.ReadBytes(countSkinData));
                        Log.Debug("Decompressed skinData" + skinData);
                    }
                    catch (Exception e)
                    {
                        Log.Error("Parsing login", e);
                        return;
                    }
                }
            }


            try
            {
                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("Input SKIN string: " + skinData);
                    }

                    IDictionary <string, dynamic> headers = JWT.Headers(skinData);
                    dynamic payload = JObject.Parse(JWT.Payload(skinData));

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Header: {string.Join(";", headers)}");
                    }
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"Skin JWT Payload:\n{payload.ToString()}");
                    }

                    // Skin JWT Payload:

                    //{
                    //	"ADRole": 2,
                    //	"ClientRandomId": -1256727416,
                    //	"CurrentInputMode": 2,
                    //	"DefaultInputMode": 2,
                    //	"DeviceModel": "SAMSUNG GT-P5210",
                    //	"DeviceOS": 1,
                    //	"GameVersion": "1.0.3.0",
                    //	"GuiScale": 0,
                    //	"ServerAddress": "192.168.0.3:19132",
                    //	"SkinData": "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Af/3/wH/9/8B//f/Af/3/wAAAP/yrmj/8q5o//KuaP/yrmj/8q5o//KuaP/yrmj/8q5o/wMCAv8B//f/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD//wAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgD/AQEB/wEBAf8BAQH//fn2//359v/9+fb//fn2/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUF/wkICP8JCQn/EhIS//KuaP/yrmj/AAAA/wkJCf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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",
                    //	"SkinId": "Standard_Custom",
                    //	"TenantId": "",
                    //	"UIProfile": 1
                    //}

                    try
                    {
                        _playerInfo.ADRole           = payload.ADRole;
                        _playerInfo.ClientId         = payload.ClientRandomId;
                        _playerInfo.CurrentInputMode = payload.CurrentInputMode;
                        _playerInfo.DefaultInputMode = payload.DefaultInputMode;
                        _playerInfo.DeviceModel      = payload.DeviceModel;
                        _playerInfo.DeviceOS         = payload.DeviceOS;
                        _playerInfo.GameVersion      = payload.GameVersion;
                        _playerInfo.GuiScale         = payload.GuiScale;
                        _playerInfo.ServerAddress    = payload.ServerAddress;
                        _playerInfo.UIProfile        = payload.UIProfile;

                        _playerInfo.Skin = new Skin()
                        {
                            SkinType = payload.SkinId,
                            Texture  = Convert.FromBase64String((string)payload.SkinData),
                        };
                    }
                    catch (Exception e)
                    {
                        Log.Error("Skin info", e);
                    }
                }

                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("Input JSON string: " + certificateChain);
                    }

                    dynamic json = JObject.Parse(certificateChain);

                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug($"JSON:\n{json}");
                    }

                    string validationKey = null;
                    foreach (dynamic o in json.chain)
                    {
                        IDictionary <string, dynamic> headers = JWT.Headers(o.ToString());

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug("Raw chain element:\n" + o.ToString());
                            Log.Debug($"JWT Header: {string.Join(";", headers)}");

                            dynamic jsonPayload = JObject.Parse(JWT.Payload(o.ToString()));
                            Log.Debug($"JWT Payload:\n{jsonPayload}");
                        }

                        // x5u cert (string): MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V
                        if (headers.ContainsKey("x5u"))
                        {
                            string certString = headers["x5u"];

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"x5u cert (string): {certString}");
                                ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(certString);
                                Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                            }

                            // Validate
                            CngKey          newKey = CryptoUtils.ImportECDsaCngKeyFromString(certString);
                            CertificateData data   = JWT.Decode <CertificateData>(o.ToString(), newKey);

                            if (data != null)
                            {
                                if (Log.IsDebugEnabled)
                                {
                                    Log.Debug("Decoded token success");
                                }

                                if (CertificateData.MojangRootKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    Log.Debug("Got Mojang key. Is valid = " + data.CertificateAuthority);
                                    validationKey = data.IdentityPublicKey;
                                }
                                else if (validationKey != null && validationKey.Equals(certString, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    _playerInfo.CertificateData = data;
                                }
                                else
                                {
                                    if (data.ExtraData == null)
                                    {
                                        continue;
                                    }

                                    // Self signed, make sure they don't fake XUID
                                    if (data.ExtraData.Xuid != null)
                                    {
                                        Log.Warn("Received fake XUID from " + data.ExtraData.DisplayName);
                                        data.ExtraData.Xuid = null;
                                    }

                                    _playerInfo.CertificateData = data;
                                }
                            }
                            else
                            {
                                Log.Error("Not a valid Identity Public Key for decoding");
                            }
                        }
                    }

                    //TODO: Implement disconnect here

                    {
                        _playerInfo.Username = _playerInfo.CertificateData.ExtraData.DisplayName;
                        _session.Username    = _playerInfo.Username;
                        string identity = _playerInfo.CertificateData.ExtraData.Identity;

                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug($"Connecting user {_playerInfo.Username} with identity={identity}");
                        }
                        _playerInfo.ClientUuid = new UUID(identity);

                        _session.CryptoContext = new CryptoContext
                        {
                            UseEncryption = Config.GetProperty("UseEncryptionForAll", false) || (Config.GetProperty("UseEncryption", true) && !string.IsNullOrWhiteSpace(_playerInfo.CertificateData.ExtraData.Xuid)),
                        };

                        if (_session.CryptoContext.UseEncryption)
                        {
                            ECDiffieHellmanPublicKey publicKey = CryptoUtils.CreateEcDiffieHellmanPublicKey(_playerInfo.CertificateData.IdentityPublicKey);
                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"Cert:\n{publicKey.ToXmlString()}");
                            }

                            // Create shared shared secret
                            ECDiffieHellmanCng ecKey = new ECDiffieHellmanCng(384);
                            ecKey.HashAlgorithm         = CngAlgorithm.Sha256;
                            ecKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                            ecKey.SecretPrepend         = Encoding.UTF8.GetBytes("RANDOM SECRET");                     // Server token

                            byte[] secret = ecKey.DeriveKeyMaterial(publicKey);

                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug($"SECRET KEY (b64):\n{Convert.ToBase64String(secret)}");
                            }

                            {
                                RijndaelManaged rijAlg = new RijndaelManaged
                                {
                                    BlockSize    = 128,
                                    Padding      = PaddingMode.None,
                                    Mode         = CipherMode.CFB,
                                    FeedbackSize = 8,
                                    Key          = secret,
                                    IV           = secret.Take(16).ToArray(),
                                };

                                // Create a decrytor to perform the stream transform.
                                ICryptoTransform decryptor      = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream     inputStream    = new MemoryStream();
                                CryptoStream     cryptoStreamIn = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read);

                                ICryptoTransform encryptor       = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                                MemoryStream     outputStream    = new MemoryStream();
                                CryptoStream     cryptoStreamOut = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);

                                _session.CryptoContext.Algorithm       = rijAlg;
                                _session.CryptoContext.Decryptor       = decryptor;
                                _session.CryptoContext.Encryptor       = encryptor;
                                _session.CryptoContext.InputStream     = inputStream;
                                _session.CryptoContext.OutputStream    = outputStream;
                                _session.CryptoContext.CryptoStreamIn  = cryptoStreamIn;
                                _session.CryptoContext.CryptoStreamOut = cryptoStreamOut;
                            }

                            var response = McpeServerToClientHandshake.CreateObject();
                            response.NoBatch         = true;
                            response.ForceClear      = true;
                            response.serverPublicKey = Convert.ToBase64String(ecKey.PublicKey.GetDerEncoded());
                            response.tokenLength     = (short)ecKey.SecretPrepend.Length;
                            response.token           = ecKey.SecretPrepend;

                            _session.SendPackage(response);

                            if (Log.IsDebugEnabled)
                            {
                                Log.Warn($"Encryption enabled for {_session.Username}");
                            }
                        }
                    }
                }

                if (!_session.CryptoContext.UseEncryption)
                {
                    _session.MessageHandler.HandleMcpeClientToServerHandshake(null);
                }
            }
            catch (Exception e)
            {
                Log.Error("Decrypt", e);
            }
        }
コード例 #35
0
        public virtual void HandleMcpeLogin(McpeLogin message)
        {
            //Disconnect("Este servidor ya no existe. Por favor, conecta a " + ChatColors.Aqua + "play.bladestorm.net" + ChatColors.White + " para seguir jugando.");
            ////Disconnect("This server is closed. Please connect to " + ChatColors.Aqua + "play.bladestorm.net" + ChatColors.White + " to continue playing.");
            //return;

            // Only one login!
            lock (_loginSyncLock)
            {
                if (_session.Username != null)
                {
                    Log.Info($"Player {_session.Username} doing multiple logins");
                    return; // Already doing login
                }

                _session.Username = string.Empty;
            }

            if (message.protocolVersion != 81)
            {
                _session.Disconnect($"Wrong version ({message.protocolVersion}) of Minecraft Pocket Edition, please upgrade.");
                return;
            }

            // THIS counter exist to protect the level from being swamped with player list add
            // attempts during startup (normally).

            DecodeCert(message);

            //if (!message.username.Equals("gurun") && !message.username.Equals("TruDan") && !message.username.Equals("Morehs"))
            //{
            //	if (serverInfo.NumberOfPlayers > serverInfo.MaxNumberOfPlayers)
            //	{
            //		Disconnect("Too many players (" + serverInfo.NumberOfPlayers + ") at this time, please try again.");
            //		return;
            //	}

            //	// Use for loadbalance only right now.
            //	if (serverInfo.ConnectionsInConnectPhase > serverInfo.MaxNumberOfConcurrentConnects)
            //	{
            //		Disconnect("Too many concurrent logins (" + serverInfo.ConnectionsInConnectPhase + "), please try again.");
            //		return;
            //	}
            //}

            //if (message.username == null || message.username.Trim().Length == 0 || !Regex.IsMatch(message.username, "^[A-Za-z0-9_-]{3,56}$"))
            //{
            //	Disconnect("Invalid username.");
            //	return;
            //}

            ////string fileName = Path.GetTempPath() + "Skin_" + Skin.SkinType + ".png";
            ////Log.Info($"Writing skin to filename: {fileName}");
            ////Skin.SaveTextureToFile(fileName, Skin.Texture);
        }