public static ChunkColumn DecocedChunkColumn(byte[] buffer) { return null; MemoryStream stream = new MemoryStream(buffer); { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); ChunkColumn chunk = new ChunkColumn(); chunk.x = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); chunk.z = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); int chunkSize = 16*16*128; defStream.Read(chunk.blocks, 0, chunkSize); defStream.Read(chunk.metadata.Data, 0, chunkSize/2); defStream.Read(chunk.skylight.Data, 0, chunkSize/2); defStream.Read(chunk.blocklight.Data, 0, chunkSize/2); defStream.Read(chunk.height, 0, 256); byte[] ints = new byte[256*4]; defStream.Read(ints, 0, ints.Length); int j = 0; for (int i = 0; i < ints.Length; i = i + 4) { chunk.biomeColor[j++] = BitConverter.ToInt32(new[] {ints[i], ints[i + 1], ints[i + 2], ints[i + 3]}, 0); } return chunk; } }
public static ChunkColumn DecocedChunkColumn(byte[] buffer) { return(null); MemoryStream stream = new MemoryStream(buffer); { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); ChunkColumn chunk = new ChunkColumn(); chunk.x = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); chunk.z = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); int chunkSize = 16 * 16 * 128; defStream.Read(chunk.blocks, 0, chunkSize); defStream.Read(chunk.metadata.Data, 0, chunkSize / 2); defStream.Read(chunk.skylight.Data, 0, chunkSize / 2); defStream.Read(chunk.blocklight.Data, 0, chunkSize / 2); defStream.Read(chunk.height, 0, 256); byte[] ints = new byte[256 * 4]; defStream.Read(ints, 0, ints.Length); int j = 0; for (int i = 0; i < ints.Length; i = i + 4) { chunk.biomeColor[j++] = BitConverter.ToInt32(new[] { ints[i], ints[i + 1], ints[i + 2], ints[i + 3] }, 0); } return(chunk); } }
internal override bool ReadTag(NbtBinaryReader readStream) { if (readStream.Selector != null && !readStream.Selector(this)) { readStream.ReadInt32(); return(false); } Value = readStream.ReadInt32(); return(true); }
public void Import(byte[] data) { using (var stream = new MemoryStream(data)) { var reader = new NbtBinaryReader(stream, false); Health = reader.ReadInt32(); Air = reader.ReadInt16(); FireTick = reader.ReadInt32(); IsOnFire = reader.ReadBoolean(); } }
internal override void SkipTag(NbtBinaryReader readStream) { int length = readStream.ReadInt32(); if (length < 0) { throw new NbtFormatException("Negative length given in TAG_Byte_Array"); } readStream.Skip(length); }
internal void HandlePackage(Package message, PlayerNetworkSession playerSession) { if (message == null) return; TraceReceive(message); if (typeof (UnknownPackage) == message.GetType()) { return; } if (typeof (McpeBatch) == message.GetType()) { McpeBatch batch = (McpeBatch) message; var messages = new List<Package>(); // Get bytes byte[] payload = batch.payload; // Decompress bytes MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { // Get actual package out of bytes MemoryStream destination = new MemoryStream(); defStream2.CopyTo(destination); destination.Position = 0; NbtBinaryReader reader = new NbtBinaryReader(destination, true); int len = reader.ReadInt32(); byte[] internalBuffer = reader.ReadBytes(len); //byte[] internalBuffer = destination.ToArray(); messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer)); if (destination.Length > destination.Position) throw new Exception("Have more data"); } foreach (var msg in messages) { msg.DatagramSequenceNumber = batch.DatagramSequenceNumber; msg.OrderingChannel = batch.OrderingChannel; msg.OrderingIndex = batch.OrderingIndex; HandlePackage(msg, playerSession); msg.PutPool(); } return; } Player player = playerSession.Player; if (player != null) player.HandlePackage(message); }
internal override bool ReadTag(NbtBinaryReader readStream) { int length = readStream.ReadInt32(); if (length < 0) { throw new NbtFormatException("Negative length given in TAG_Int_Array"); } if (readStream.Selector != null && !readStream.Selector(this)) { readStream.Skip(length * sizeof(int)); return(false); } Value = new int[length]; for (int i = 0; i < length; i++) { Value[i] = readStream.ReadInt32(); } return(true); }
private void OnBatch(Package message) { McpeBatch batch = (McpeBatch)message; var messages = new List <Package>(); // Get bytes byte[] payload = batch.payload; // Decompress bytes MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { // Get actual package out of bytes MemoryStream destination = new MemoryStream(); defStream2.CopyTo(destination); destination.Position = 0; NbtBinaryReader reader = new NbtBinaryReader(destination, true); do { int len = reader.ReadInt32(); byte[] internalBuffer = reader.ReadBytes(len); var package = PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer); messages.Add(package); if (!(package is McpeFullChunkData)) { Log.Debug($"Batch: {package.GetType().Name} 0x{package.Id:x2} \n{Package.HexDump(internalBuffer)}"); } } while (destination.Position < destination.Length); } foreach (var msg in messages) { msg.DatagramSequenceNumber = batch.DatagramSequenceNumber; msg.OrderingChannel = batch.OrderingChannel; msg.OrderingIndex = batch.OrderingIndex; HandlePackage(msg); msg.PutPool(); } }
internal override bool ReadTag(NbtBinaryReader readStream) { int length = readStream.ReadInt32(); if (length < 0) { throw new NbtFormatException("Negative length given in TAG_Byte_Array"); } if (readStream.Selector != null && !readStream.Selector(this)) { readStream.Skip(length); return false; } Value = readStream.ReadBytes(length); if (Value.Length < length) { throw new EndOfStreamException(); } return true; }
private List <Package> HandleBatch(McpeWrapper batch) { var messages = new List <Package>(); // Get bytes byte[] payload = batch.payload; // Decompress bytes Console.WriteLine("Package:\n" + Package.HexDump(payload)); MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { // Get actual package out of bytes MemoryStream destination = new MemoryStream(); defStream2.CopyTo(destination); destination.Position = 0; NbtBinaryReader reader = new NbtBinaryReader(destination, true); int len = reader.ReadInt32(); byte[] internalBuffer = reader.ReadBytes(len); Console.WriteLine($"Package [len={len}:\n" + Package.HexDump(internalBuffer)); messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer, "mcpe") ?? new UnknownPackage(internalBuffer[0], internalBuffer)); if (destination.Length > destination.Position) { throw new Exception("Have more data"); } } return(messages); }
private void HandleChunk(byte[] chunkData, int cx, int cz, Action <ChunkColumn> callback) { MeasureProfiler.StartCollectingData(); var profiler = MiniProfiler.StartNew("BEToJavaColumn"); try { using (MemoryStream stream = new MemoryStream(chunkData)) { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); int count = defStream.ReadByte(); if (count < 1) { Log.Warn("Nothing to read"); return; } ChunkColumn chunkColumn = new ChunkColumn(); chunkColumn.IsDirty = true; chunkColumn.X = cx; chunkColumn.Z = cz; for (int s = 0; s < count; s++) { var section = chunkColumn.Sections[s] as ChunkSection; if (section == null) { section = new ChunkSection(s, true); } int version = defStream.ReadByte(); if (version == 1 || version == 8) { int storageSize = defStream.ReadByte(); for (int storage = 0; storage < storageSize; storage++) { int paletteAndFlag = defStream.ReadByte(); bool isRuntime = (paletteAndFlag & 1) != 0; int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096.0f / blocksPerWord); uint[] words = new uint[wordCount]; for (int w = 0; w < wordCount; w++) { int word = defStream.ReadInt32(); words[w] = SwapBytes((uint)word); } uint[] pallete = new uint[0]; if (isRuntime) { int palleteSize = VarInt.ReadSInt32(stream); pallete = new uint[palleteSize]; for (int pi = 0; pi < pallete.Length; pi++) { var ui = (uint)VarInt.ReadSInt32(stream); pallete[pi] = ui; } if (palleteSize == 0) { Log.Warn($"Pallete size is 0"); continue; } } int position = 0; for (int w = 0; w < wordCount; w++) { uint word = words[w]; for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { break; // padding bytes } uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (storage == 0) { if (state >= pallete.Length) { continue; } IBlockState translated = _convertedStates.GetOrAdd(pallete[state], u => { if (_blockStateMap.TryGetValue(pallete[state], out var bs)) { var result = BlockFactory.RuntimeIdTable.FirstOrDefault(xx => xx.Name == bs.Name); if (result != null && result.Id >= 0) { var reverseMap = MiNET.Worlds.AnvilWorldProvider.Convert.FirstOrDefault(map => map.Value.Item1 == result.Id); var id = result.Id; if (reverseMap.Value != null) { id = reverseMap.Key; } var res = BlockFactory.GetBlockStateID( (int)id, (byte)bs.Data); if (AnvilWorldProvider.BlockStateMapper.TryGetValue( res, out var res2)) { var t = BlockFactory.GetBlockState(res2); t = TranslateBlockState(t, id, bs.Data); return(t); } else { Log.Info( $"Did not find anvil statemap: {result.Name}"); return(TranslateBlockState( BlockFactory.GetBlockState(result.Name), id, bs.Data)); } } return(TranslateBlockState( BlockFactory.GetBlockState(bs.Name), -1, bs.Data)); } return(null); }); if (translated != null) { section.Set(x, y, z, translated); } } else { //TODO. } position++; } if (position >= 4096) { break; } } } } else { #region OldFormat byte[] blockIds = new byte[4096]; defStream.Read(blockIds, 0, blockIds.Length); NibbleArray data = new NibbleArray(4096); defStream.Read(data.Data, 0, data.Data.Length); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int idx = (x << 8) + (z << 4) + y; var id = blockIds[idx]; var meta = data[idx]; IBlockState result = null; if (id > 0 && result == null) { var res = BlockFactory.GetBlockStateID(id, meta); if (AnvilWorldProvider.BlockStateMapper.TryGetValue(res, out var res2)) { var t = BlockFactory.GetBlockState(res2); t = TranslateBlockState(t, id, meta); result = t; } else { Log.Info($"Did not find anvil statemap: {result.Name}"); result = TranslateBlockState(BlockFactory.GetBlockState(res), id, meta); } } if (result == null) { var results = BlockFactory.RuntimeIdTable.Where(xx => xx.Id == id && xx.Data == meta).ToArray(); if (results.Length > 0) { result = TranslateBlockState( BlockFactory.GetBlockState((uint)results[0].RuntimeId), id, meta); } } if (result != null) { section.Set(x, y, z, result); } } } } #endregion } if (UseAlexChunks) { // Log.Info($"Alex chunk!"); var rawSky = new Utils.NibbleArray(4096); defStream.Read(rawSky.Data, 0, rawSky.Data.Length); var rawBlock = new Utils.NibbleArray(4096); defStream.Read(rawBlock.Data, 0, rawBlock.Data.Length); for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { var peIndex = (x * 256) + (z * 16) + y; var sky = rawSky[peIndex]; var block = rawBlock[peIndex]; var idx = y << 8 | z << 4 | x; section.SkyLight[idx] = sky; section.BlockLight[idx] = block; } } } } section.RemoveInvalidBlocks(); section.IsDirty = true; //Make sure the section is saved. chunkColumn.Sections[s] = section; } byte[] ba = new byte[512]; if (defStream.Read(ba, 0, 256 * 2) != 256 * 2) { Log.Error($"Out of data height"); } Buffer.BlockCopy(ba, 0, chunkColumn.Height, 0, 512); int[] biomeIds = new int[256]; for (int i = 0; i < biomeIds.Length; i++) { biomeIds[i] = defStream.ReadByte(); } chunkColumn.BiomeId = biomeIds; if (stream.Position >= stream.Length - 1) { callback?.Invoke(chunkColumn); return; } int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock > 0) { byte[] buf = new byte[borderBlock]; int len = defStream.Read(buf, 0, borderBlock); } if (stream.Position < stream.Length - 1) { while (stream.Position < stream.Length) { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); } } if (stream.Position < stream.Length - 1) { Log.Warn( $"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); } //Done processing this chunk, send to world callback?.Invoke(chunkColumn); } } catch (Exception ex) { Log.Error($"Exception in chunk loading: {ex.ToString()}"); } finally { profiler?.Stop(); MeasureProfiler.SaveData(); } }
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); } }
internal override void SkipTag(NbtBinaryReader readStream) { readStream.ReadInt32(); }
internal override bool ReadTag(NbtBinaryReader readStream) { if (readStream.Selector != null && !readStream.Selector(this)) { readStream.ReadInt32(); return false; } Value = readStream.ReadInt32(); return true; }
internal override bool ReadTag(NbtBinaryReader readStream) { if (readStream.Selector != null && !readStream.Selector(this)) { SkipTag(readStream); return(false); } ListType = readStream.ReadTagType(); int length = readStream.ReadInt32(); if (length < 0) { throw new NbtFormatException("Negative list size given."); } for (int i = 0; i < length; i++) { NbtTag newTag; switch (ListType) { case NbtTagType.Byte: newTag = new NbtByte(); break; case NbtTagType.Short: newTag = new NbtShort(); break; case NbtTagType.Int: newTag = new NbtInt(); break; case NbtTagType.Long: newTag = new NbtLong(); break; case NbtTagType.Float: newTag = new NbtFloat(); break; case NbtTagType.Double: newTag = new NbtDouble(); break; case NbtTagType.ByteArray: newTag = new NbtByteArray(); break; case NbtTagType.String: newTag = new NbtString(); break; case NbtTagType.List: newTag = new NbtList(); break; case NbtTagType.Compound: newTag = new NbtCompound(); break; case NbtTagType.IntArray: newTag = new NbtIntArray(); break; default: // should never happen, since ListType is checked beforehand throw new NbtFormatException("Unsupported tag type found in a list: " + ListType); } newTag.Parent = this; if (newTag.ReadTag(readStream)) { tags.Add(newTag); } } return(true); }
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": "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", // "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); } }
public void LabTest() { // x = 8, z = 9 string test = "78daedcdc109c0200004c1233e125bb32f1b4a836a170acec0bef74b52576f294f36f2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f73fe10f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002718974bff9ba43b9b1d578f30"; string test2 = "789ced5dc9721cc711ed8e09c5486341185877872f085c110179df480220099120294ba47ce4cd115ee99dd64aefa6f7332fd09d3cf80374d00f38829f40ff8088b32f7067cfd44cf774d792f5b23bd14065c470d033fdea655657d6cbaa6e80af6459f6bf939393f1789c57acf8340fb6a3a3a39733d0e6fc930991133d833f17e1cfc7444f0ecc3ee93ffe71959f15be007f3eeffff202f0f865fabf320099f422fc4533c6017ef862e33f8a5f26fe053f9b5ee8fa03e10b8f3fae29f34b8f3f1dfe687ac9f94f317e881f76405dfff3790130e3ee9f7fbcd0bfd907e1f452f3ef78c63fc9caf8fbe65fc43fe130cfe9cfc4fc5b51400dfee8f2435d7fb5f9e5eb2f6ef8eaf3ff19e08fa63f23f143f59f80fee7d50a28eb5f7fabf31f73052837fee6facfe0968bdf6c40b0f985d6bf950d0085f8e76d45d0abafbf64f54fe9fa2ff29ff835f47fd15a04bd74fdc1e3971a7fb1035078fe55e257d75f845f447f117ed401b3fe9e5ba6a0ff739b1075fffbdfcb05302bf64ef879f4a2fb5f31fa2fa93f547ff1e985f557833f371ea88dbf65fc4af5472cbfdcfdb799a95cff61eb9f363faebfd8febf84feeaf2afeefff3f8a5f59f1bff19e05f14006c7ed1f9577dfd3d61872fbbfe52ebff45fcbafaa3a5bfa635edfa8b6fa760ff577bfd2f7dffb97f7e75fd8da69ff1830ee8afffb5d75faef9d7ed91ecfaa3853f73778974fccdf07be07726602ffcb9895f5d7f99fc67abfee01bf17f1ee5cf21fd3d03fa87e93fbefe8db7230101c4f517f300ad3f9e3c295e474f80f8eb1e54e680f27b0fbfe8fcb7d2bc8f5e7cfdc976a0077e9703d2fad720f0f00b3fffd5b45ee3b738d039bfcb016d7e8f75b1fe9d4e19f4eaf587bafe4becff02fb1ff8fa934fbf182122facb0fbec63fd7df680146fbdff0c73ae0609f9de07640f6f9eb167e4f0708d4ffc65aeb8feee3cfedeb3faf0392f3efc4a2ffddf32ff63fb8fc92cf1fb65b0ffc3efdefbaff1bebdfaafebae93be167e8bfc40540f7bf859fbfeadd01b0fe13d87f666f40b4e92f107f04ffb4c11fafbf31f5471b7fa40b8eeb3f3bc1e549b7f35f4ffcd6eb9f791d90dc7f6dd15f1fbfe8fd476dfd8fe0efe3fe431ffa6b77a097f8eb365dd1ffbefbbfaeffbefd8fe1afbfa3d9651c80e347f7df65f6bf91f5377fffa15d7fa3f945ea8f2771559067f2e9a1fe57e6470a90b3a0bfb983bf870d7867fc9e0e10baff99c7f24bdc80aed47f2d0499d38191ccf347e6fed3ec6dda2800acfc42cf3fadee3f04172002dbbf3efd73d18bdd7f8d3611fd2bda595f8fa5175aff0af047eb9fbdff7d5b510dfe080f5c97dfc6df76ff61c67f741411bf53ff3c1d2052ffbb1cf0f0775cff7b1c90d43f1b7fc70b2070ff5beef75f22f557ecf9db56fe00fdc3ef7f2af393030715feeaac9305f0c3cf5fadd43f3c7e587f97e38fdbfd65fdb59c7f63e31f3bea3ffffe4787fbbf5e13d1df72fbb5b500f1de0912d25f5b0f4cf9fa7fc4f6c0a9ffecf84b63f263f5a7e6fe9b8cfee93e00a4fefb1f1e077cf58fc4f33ff3fdff567a3277fca8fe78eb0fab0372fc07083fbafe1dfbf4bf537e7ffd67e31fc9ac3ffdfc96f04775fd8fd5dfdcc36f61cf57eb8fb85d007ffd69e7175dff36f923f43f427f4d6366fe595b83f8b91eacaeffd6d6960ef8cca2ffac6180fcfd2919fdd3d65fdd07803cfcdefa5f60fde5e02f4ff13980ea9ff71650d7fa375f8069f1cf1a73ecffdb1c381270a0f2fc85167ff5fecf68340aeeffbafec7df7fa5b60e2625ffa895bf9dbec11fbdff3cce677fffab3d7e0b7b1b7f94fe9af27ba6bf35fa7cddc5dfa63f6c0766fcebeb9386fe97f2cbe58fd1dfbc1a7fbe22bf7c7ebefe56f9fdfabf2c4bacfc8c2d0044fe2af79f587dbe127f34bdd0fd2ff70d0037bddcfac342ef73406cffd1caef70416efe75f33bf4e714f147afff7c8fe074cb5f63afcb0f8f3ffefeeb41b9ff50fcdbaebfaefa4b40ff2afa3b5a71c049dfa2bfb1fa67fefe675bfc16f676fe88f56f957fb5fec85f7238d0ca1fa3bfe38afe33f865f437afe96f117f4d7e1bfcebeb01facb7060b5fe28f86b0e34e20fe167dc0370de7ff7589d9fd1e92df1b75bd608dfce1f39ff7be49fc11f3bff47dfff179a7ffdfadfe5fcefed7fbb030dfe98fd4fe7affff4c01f547f04f203ebbf7ca6c298fe47de7f2d1b2bf71f2cfa1fcc1f7fff3542ffdbe75fa603e3e5ffbfd1a2ffa43f36769bfef23c30f3bf9cfe73d7bfd5fe67f10be9ef32fe207e71fd5dad3f6a2ef4c06fedde9cb7feece2f91337bf8cfec5c72f34ff47ff0a840cbf2f7ebb07c2fae3e0ef52ff42e20fe58f58ff39cbef1ef89d05681ffcb5df7f85f5ff88fdfc53ee5affe6ae2d4011fd5dfeff1badfc0bf2e9b4b1312ca3bf35fe95fdff4afd315ddd1997dd7f6eeeff1bfe08fde7e96f3eef80f24da4fe88d0ff257fad0088e567ff1e40bb6d6c60f8298847f9b5fdd78effbcfbaf3d7ef4f1b9ffa44ef931fc791fbf43c76b8f9f84d7cd7fedf13374fea1e3b5fb4f3fff503c9abf9803faf1ebe2cffbf83beff10f3f7fcf77fe6beb9f365ebbff878f47f3573dff2107f4fb3fe1111bfefc31f8fc831ad8001bf8efa7d9e7a6103f00ce86af7fdafc91f8db5278fdf8d5f317d4cf5ef27707c45b4d3b7f078a17cbbf38fcaddb2fcc7f8af31fc1eface0b9e953c7b3b367bb4c85cafc85e52f8a47f32fe53f8657d27f9dfcdd7eb581e7f19bb18ee0b757f09cf4294ede46f2bf89e7e5ef34cf76eaf3074fbe8babb5534f455efe15f8ed51047e7b6764f9668e8f9e02b4f3571fafb2feace81703bf6d82ad8d7f0ebe25ff99f9d7c4332230644b3c2b7fc8d91d4a8525fe191f1fcd3fa5584bfcc6e2fab1f26fc1bfec7383773730cfff0d9a7f46edf84f03835831edfcc1f1baf74f58fc3bcd328e953e3baf363ee2e117e7c6e9df4633ffb9f9b38ae7e46f891fd5eb0f36ff8afe73f2b7ac352cf91fd2c0023f6dc1bbf37767e9bf2dff5f8c4a24edfc13c85fd5f51f2b7fdaf31fc6070700e2dbc60a33ff1a0d30f3df860fcddf62fea87f1699bf0b3f38fa3bc38f2cf81703f00bfd6fc347e6bf6efef69a7fedfcf0fd9bbef2cf860f0e00c56f34f1bcfcb7ce1f81f96bc787e56ff3b305fe153f7ed15191f95be2b7b35ad270f2b764ddb1f2e7cffc21348cb57eea008fee5f0ecaff96fc3b25f8b0261cf8a006c0fc6b338efe965973cf86f7e6ef2c6bef66d6fc0bc2df8ac65754df92ff117dd8d3fd8baef1d14df48adf6eeee2f69a7f5de223f79f58fa49ffd8f3372c7fee46e397f91b577fcff017ec785ffe4e3bc87f21fd1b46fe39f0b10d88e143ae9d63fe08c2bbf217e50fc9bf96cf58f9333b635a3d31423fa7f42717daf0cf02f11b597bfdeecbbf0a1ec9dfda32a6868f9a834f3c96f0099ff0a7177f3c70ff133ee1133e1e9ff23fe1137eb878347f7d0e9cf6f8133ee1878cd7cedf94ff099ff0f178347fd5f3dfe300489ff009df297ef0f9e769c08f77371080777601187ec2277ca778f5fc05f5d3e74100ded94008de1502e47cc227bcc7069fbf78fe43faeb6b2004efeac47864c227fc39c87fbc7e87f5db154310ded100e2fb79c06baf3fd5f307c57b22f0e371fd44f1b8fec6e79faf8140bcb50f6271a1f8733ffe51bc7afd8ae2f1fc75b9108407ea5f5f0861783c7f6d0d84e26d0d443b1ecaaf8d1f7cfea078547f61fd565dbffa1a08c40f367f7d0d7861d69eeb099ff20fc4c3fbcf285e75fdea6b20101f5d3ffb3c08c6c7e6af278478cfc3f9513cac1f281e1dbff0f8d7c60f3fff06abbf4b43f1ad0ec43333f0eae31f1dbff0f8d7c6a3f9a75fffa2784b03e1f801e72f8cb7747e303ee50f8887f54f1b8feb278a3fcff96b0f60fed5dd7d4e432b7ead6793fb77e2f185138f1f7e17c27ffcc8fff761ac767c927df4701c8f2fec5ff72178f608c43f7e08c13f79fc1284ff37d2fdc94e81dd03f2375bffe4f103207f8f4f9e82f9fbfc3f0f80fc3d3e598f07cbd84718fce9c713553c3a7f648f307832d410fda7f183cc1f94ff083be53f82cfd0fc6715615d18187f81ff0c84c7ae1fcd1f183e196ab75e43d0cfd7eebee03fcb6a70fe3e5fc3f068fe3fc5f019e8bf40feebe2b397417c32d02ed8fe07b12083c72f863f46f110bab0e7285eb7fff0fc07f99369dbf66711b4faf845f1181c36f5f853fe9e7783fe9b9dc1eb1f064f962c1960caf3c731cc0fe293254b166d68fe6ae393254b166fdaf9ab8e479f5f507ffe2159b2e19a7afe6be3c1f9431b9f2c1962f0f8d5cedf84d7c5a7f9eb7cdbc0f5131dff2709af8a4f960c3174fec0c73ff8fc278c87e0eaf864c9104bf90fc1d5f1c9922186d7ffdaf9ab9bff9aebb70b4bbb78e9caebd7ab8797ae5e3bac1eef1e5cbfb13cbeb4bbf7fae18dead77bd70e6f568ef7f6afdda81cefeeed5fbf71ab02dfbf7cfd66e5786ffff2e1e2f8e2c5fd2b07d76ebef1e6fce812f97678ebdb6f19aeddabd76fdc7ce3addbe670efa000bf79fb4e79f6dee52b570f0bf0ed3b6f97715cbe5ab6551cbe4d4ded5e3928da2a0fbfb3f9c75f5e285f7ff8c5b7367ff393af6dbeffc32f6d3eb8f7d5cd77bfff85cdf77ef0c5f2b3dffdec1be5f70f7fbd5b9efbd777f737ff7cffd2e69f7e75b13c36e77cf8e3af2cdee9f5c18fbe5cbe1b2c61e8e72a1f7d46c7bffde9d7cbf3e945bc744cdf932ff4fafdcfbfb938d7bce87b6a97380943af77bef75af939f94f6dd177f432fed2cfd577f283da270c9d6fb0f419f94efd41be5431745cf8b365e2228c899770e483698bdec95783233fe855e04abcf98c7888975ef4b3e1357dfa9777f6ca77ea076a6fde46796cda212e3a3631d3e7744ce7d1cf7f7bef72f9fac70757cb776a93aea56983de4dcce61ad2e7868bcefffbfb57ca9f291e3aa677131b9d6fae17e1e8736ad38c13c29a971947c607331e8cdf669cd08bce31e7198c39e79f1f1e2cf0c617e32bf94ded55fbdff48de977c2527f10c68c6bc29a18cd98a7cfcd982ce2dca297e91b83317d427d6bda32d7cbf46fd1c656c1bf55f4f196191b2646931f86db5c4bea4f3a97ae0b8d71e22ec618f9b0e0a88eadf978d82adad8227fcd18a7b6e6e3abc417afff0309a69f37"; string test3 = "7801EDDC310D00000803B02508C0BF5B828A3DAD904E920900000000000000000000000000000000000000000000000000000000000000F016000000000000000000000000000000A86BFF03000000000000000000000000000000000000000000000000000000000000000040CF01072DC034"; //$ordered = zlib_encode( //int chunkX) . //int chunkZ) . //$orderedIds . //$orderedData . //$orderedSkyLight . //$orderedLight . //$this->biomeIds . //$biomeColors . //$this->tiles byte[] val = SoapHexBinary.Parse(test).Value; Assert.IsNotNull(val); MemoryStream stream = new MemoryStream(val); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { NbtBinaryReader defStream = new NbtBinaryReader(defStream2, true); ChunkColumn chunk = new ChunkColumn(); chunk.x = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); chunk.z = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); int chunkSize = 16*16*128; Assert.AreEqual(chunkSize, defStream.Read(chunk.blocks, 0, chunkSize)); Assert.AreEqual(chunkSize/2, defStream.Read(chunk.metadata.Data, 0, chunkSize/2)); Assert.AreEqual(chunkSize/2, defStream.Read(chunk.skylight.Data, 0, chunkSize/2)); Assert.AreEqual(chunkSize/2, defStream.Read(chunk.blocklight.Data, 0, chunkSize/2)); Assert.AreEqual(256, defStream.Read(chunk.biomeId, 0, 256)); byte[] ints = new byte[256*4]; Assert.AreEqual(ints.Length, defStream.Read(ints, 0, ints.Length)); int j = 0; for (int i = 0; i < ints.Length; i = i + 4) { chunk.biomeColor[j++] = BitConverter.ToInt32(new[] {ints[i], ints[i + 1], ints[i + 2], ints[i + 3]}, 0); } MemoryStream uncompressed = new MemoryStream(); int b = -1; do { b = defStream2.ReadByte(); if (b != -1) uncompressed.WriteByte((byte) b); } while (b != -1); Assert.AreEqual(0, uncompressed.Length); //Assert.AreEqual(83208, uncompressed.Length); Assert.AreEqual(8, chunk.x); Assert.AreEqual(9, chunk.z); byte[] data = chunk.GetBytes(); Assert.AreEqual(83208, data.Length); // Expected uncompressed length } }
internal override void SkipTag(NbtBinaryReader readStream) { // read list type, and make sure it's defined ListType = readStream.ReadTagType(); int length = readStream.ReadInt32(); if (length < 0) { throw new NbtFormatException("Negative list size given."); } switch (ListType) { case NbtTagType.Byte: readStream.Skip(length); break; case NbtTagType.Short: readStream.Skip(length * sizeof(short)); break; case NbtTagType.Int: readStream.Skip(length * sizeof(int)); break; case NbtTagType.Long: readStream.Skip(length * sizeof(long)); break; case NbtTagType.Float: readStream.Skip(length * sizeof(float)); break; case NbtTagType.Double: readStream.Skip(length * sizeof(double)); break; default: for (int i = 0; i < length; i++) { switch (listType) { case NbtTagType.ByteArray: new NbtByteArray().SkipTag(readStream); break; case NbtTagType.String: readStream.SkipString(); break; case NbtTagType.List: new NbtList().SkipTag(readStream); break; case NbtTagType.Compound: new NbtCompound().SkipTag(readStream); break; case NbtTagType.IntArray: new NbtIntArray().SkipTag(readStream); break; } } break; } }
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": "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", // "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); } }
private void OnBatch(Package message) { McpeBatch batch = (McpeBatch) message; var messages = new List<Package>(); // Get bytes byte[] payload = batch.payload; // Decompress bytes MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { // Get actual package out of bytes MemoryStream destination = new MemoryStream(); defStream2.CopyTo(destination); destination.Position = 0; NbtBinaryReader reader = new NbtBinaryReader(destination, true); do { int len = reader.ReadInt32(); byte[] internalBuffer = reader.ReadBytes(len); messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer)); } while (destination.Position < destination.Length); } foreach (var msg in messages) { msg.DatagramSequenceNumber = batch.DatagramSequenceNumber; msg.OrderingChannel = batch.OrderingChannel; msg.OrderingIndex = batch.OrderingIndex; HandlePackage(msg); msg.PutPool(); } }
internal void HandlePackage(Package message, PlayerNetworkSession playerSession) { Player player = playerSession.Player; if (message == null) { return; } if (typeof(McpeWrapper) == message.GetType()) { McpeWrapper batch = (McpeWrapper)message; // Get bytes byte[] payload = batch.payload; if (playerSession.CryptoContext != null && Config.GetProperty("UseEncryption", true)) { payload = CryptoUtils.Decrypt(payload, playerSession.CryptoContext); } //if (Log.IsDebugEnabled) // Log.Debug($"0x{payload[0]:x2}\n{Package.HexDump(payload)}"); var msg = PackageFactory.CreatePackage(payload[0], payload, "mcpe") ?? new UnknownPackage(payload[0], payload); HandlePackage(msg, playerSession); msg.PutPool(); return; } if (typeof(UnknownPackage) == message.GetType()) { UnknownPackage packet = (UnknownPackage)message; Log.Warn($"Received unknown package 0x{message.Id:X2}\n{Package.HexDump(packet.Message)}"); return; } if (typeof(McpeBatch) == message.GetType()) { Log.Debug("Handle MCPE batch message"); McpeBatch batch = (McpeBatch)message; var messages = new List <Package>(); // Get bytes byte[] payload = batch.payload; // Decompress bytes MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); 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, true); while (destination.Position < destination.Length) { int len = reader.ReadInt32(); byte[] internalBuffer = reader.ReadBytes(len); //if (Log.IsDebugEnabled) // Log.Debug($"0x{internalBuffer[0]:x2}\n{Package.HexDump(internalBuffer)}"); messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer, "mcpe") ?? new UnknownPackage(internalBuffer[0], internalBuffer)); } if (destination.Length > destination.Position) { throw new Exception("Have more data"); } } foreach (var msg in messages) { msg.DatagramSequenceNumber = batch.DatagramSequenceNumber; msg.OrderingChannel = batch.OrderingChannel; msg.OrderingIndex = batch.OrderingIndex; HandlePackage(msg, playerSession); msg.PutPool(); } return; } if (player != null) { player.HandlePackage(message); } }
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); } }
/// <summary> /// Handles the specified package. /// </summary> /// <param name="message">The package.</param> /// <param name="senderEndpoint">The sender's endpoint.</param> private void HandlePackage(Package message, IPEndPoint senderEndpoint) { if (typeof(McpeBatch) == message.GetType()) { Log.Debug("Processing Batch package"); McpeBatch batch = (McpeBatch)message; var messages = new List <Package>(); // Get bytes byte[] payload = batch.payload; // Decompress bytes MemoryStream stream = new MemoryStream(payload); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { // Get actual package out of bytes MemoryStream destination = new MemoryStream(); defStream2.CopyTo(destination); destination.Position = 0; NbtBinaryReader reader = new NbtBinaryReader(destination, true); do { int len = reader.ReadInt32(); byte[] internalBuffer = reader.ReadBytes(len); messages.Add(PackageFactory.CreatePackage(internalBuffer[0], internalBuffer) ?? new UnknownPackage(internalBuffer[0], internalBuffer)); } while (destination.Position < destination.Length); // throw new Exception("Have more data"); } foreach (var msg in messages) { HandlePackage(msg, senderEndpoint); msg.PutPool(); } return; } TraceReceive(message); if (typeof(UnknownPackage) == message.GetType()) { return; } if (typeof(McpeDisconnect) == message.GetType()) { McpeDisconnect msg = (McpeDisconnect)message; Log.InfoFormat("Disconnect {1}: {0}", msg.message, Username); SendDisconnectionNotification(); StopClient(); return; } if (typeof(ConnectedPing) == message.GetType()) { ConnectedPing msg = (ConnectedPing)message; SendConnectedPong(msg.sendpingtime); return; } if (typeof(McpeFullChunkData) == message.GetType()) { //McpeFullChunkData msg = (McpeFullChunkData) message; //ChunkColumn chunk = ClientUtils.DecocedChunkColumn(msg.chunkData); //if (chunk != null) //{ // Log.DebugFormat("Chunk X={0}", chunk.x); // Log.DebugFormat("Chunk Z={0}", chunk.z); // //ClientUtils.SaveChunkToAnvil(chunk); //} return; } if (typeof(ConnectionRequestAccepted) == message.GetType()) { Thread.Sleep(50); SendNewIncomingConnection(); //_connectedPingTimer = new Timer(state => SendConnectedPing(), null, 1000, 1000); Thread.Sleep(50); SendLogin(Username); return; } if (typeof(McpeSetSpawnPosition) == message.GetType()) { McpeSetSpawnPosition msg = (McpeSetSpawnPosition)message; _spawn = new Vector3(msg.x, msg.y, msg.z); _level.SpawnX = (int)_spawn.X; _level.SpawnY = (int)_spawn.Y; _level.SpawnZ = (int)_spawn.Z; return; } if (typeof(McpeStartGame) == message.GetType()) { McpeStartGame msg = (McpeStartGame)message; _entityId = msg.entityId; _spawn = new Vector3(msg.x, msg.y, msg.z); _level.LevelName = "Default"; _level.Version = 19133; _level.GameType = msg.gamemode; //ClientUtils.SaveLevel(_level); return; } if (typeof(McpeTileEvent) == message.GetType()) { McpeTileEvent msg = (McpeTileEvent)message; Log.DebugFormat("X: {0}", msg.x); Log.DebugFormat("Y: {0}", msg.y); Log.DebugFormat("Z: {0}", msg.z); Log.DebugFormat("Case 1: {0}", msg.case1); Log.DebugFormat("Case 2: {0}", msg.case2); return; } if (typeof(McpeAddEntity) == message.GetType()) { McpeAddEntity msg = (McpeAddEntity)message; Log.DebugFormat("Entity ID: {0}", msg.entityId); Log.DebugFormat("Entity Type: {0}", msg.entityType); Log.DebugFormat("X: {0}", msg.x); Log.DebugFormat("Y: {0}", msg.y); Log.DebugFormat("Z: {0}", msg.z); Log.DebugFormat("Yaw: {0}", msg.yaw); Log.DebugFormat("Pitch: {0}", msg.pitch); Log.DebugFormat("Velocity X: {0}", msg.speedX); Log.DebugFormat("Velocity Y: {0}", msg.speedY); Log.DebugFormat("Velocity Z: {0}", msg.speedZ); //Log.DebugFormat("Metadata: {0}", msg.metadata.ToString()); //Log.DebugFormat("Links count: {0}", msg.links); return; } if (typeof(McpeSetEntityData) == message.GetType()) { McpeSetEntityData msg = (McpeSetEntityData)message; Log.DebugFormat("Entity ID: {0}", msg.entityId); MetadataDictionary metadata = msg.metadata; Log.DebugFormat("Metadata: {0}", metadata.ToString()); return; } if (typeof(McpeMovePlayer) == message.GetType()) { //McpeMovePlayer msg = (McpeMovePlayer) message; //Log.DebugFormat("Entity ID: {0}", msg.entityId); //CurrentLocation = new PlayerLocation(msg.x, msg.y + 10, msg.z); //SendMcpeMovePlayer(); return; } if (typeof(McpeUpdateBlock) == message.GetType()) { McpeUpdateBlock msg = (McpeUpdateBlock)message; Log.DebugFormat("No of Blocks: {0}", msg.blocks.Count); return; } if (typeof(McpeLevelEvent) == message.GetType()) { McpeLevelEvent msg = (McpeLevelEvent)message; Log.DebugFormat("Event ID: {0}", msg.eventId); Log.DebugFormat("X: {0}", msg.x); Log.DebugFormat("Y: {0}", msg.y); Log.DebugFormat("Z: {0}", msg.z); Log.DebugFormat("Data: {0}", msg.data); return; } if (typeof(McpeContainerSetContent) == message.GetType()) { McpeContainerSetContent msg = (McpeContainerSetContent)message; Log.DebugFormat("Window ID: 0x{0:x2}, Count: {1}", msg.windowId, msg.slotData.Count); var slots = msg.slotData.GetValues(); foreach (var entry in slots) { MetadataSlot slot = (MetadataSlot)entry; //Log.DebugFormat(" - Id: {0}, Metadata: {1}, Count: {2}", slot.Value.Item.Id, slot.Value.Item.Metadata, slot.Value.Count); } return; } if (typeof(McpeCraftingData) == message.GetType()) { string fileName = Path.GetTempPath() + "Recipes_" + Guid.NewGuid() + ".txt"; Log.Info("Writing recipes to filename: " + fileName); FileStream file = File.OpenWrite(fileName); McpeCraftingData msg = (McpeCraftingData)message; IndentedTextWriter writer = new IndentedTextWriter(new StreamWriter(file)); writer.WriteLine("static RecipeManager()"); writer.WriteLine("{"); writer.Indent++; writer.WriteLine("Recipes = new Recipes"); writer.WriteLine("{"); writer.Indent++; foreach (Recipe recipe in msg.recipes) { ShapelessRecipe shapelessRecipe = recipe as ShapelessRecipe; if (shapelessRecipe != null) { writer.WriteLine(string.Format("new ShapelessRecipe(new ItemStack(ItemFactory.GetItem({0}, {1}), {2}),", shapelessRecipe.Result.Id, shapelessRecipe.Result.Metadata, shapelessRecipe.Result.Count)); writer.Indent++; writer.WriteLine("new List<ItemStack>"); writer.WriteLine("{"); writer.Indent++; foreach (var itemStack in shapelessRecipe.Input) { writer.WriteLine(string.Format("new ItemStack(ItemFactory.GetItem({0}, {1}), {2}),", itemStack.Id, itemStack.Metadata, itemStack.Count)); } writer.Indent--; writer.WriteLine("}),"); writer.Indent--; continue; } ShapedRecipe shapedRecipe = recipe as ShapedRecipe; if (shapedRecipe != null) { writer.WriteLine(string.Format("new ShapedRecipe({0}, {1}, new ItemStack(ItemFactory.GetItem({2}, {3}), {4}),", shapedRecipe.Width, shapedRecipe.Height, shapedRecipe.Result.Id, shapedRecipe.Result.Metadata, shapedRecipe.Result.Count)); writer.Indent++; writer.WriteLine("new Item[]"); writer.WriteLine("{"); writer.Indent++; foreach (Item item in shapedRecipe.Input) { writer.WriteLine(string.Format("ItemFactory.GetItem({0}, {1}),", item.Id, item.Metadata)); } writer.Indent--; writer.WriteLine("}),"); writer.Indent--; continue; } } writer.WriteLine("};"); writer.Indent--; writer.WriteLine("}"); writer.Indent--; writer.Flush(); file.Close(); Environment.Exit(0); return; } }
public void LabTest() { // x = 8, z = 9 string test = "78daedcdc109c0200004c1233e125bb32f1b4a836a170acec0bef74b52576f294f36f2f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f73fe10f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002718974bff9ba43b9b1d578f30"; string test2 = "789ced5dc9721cc711ed8e09c5486341185877872f085c110179df480220099120294ba47ce4cd115ee99dd64aefa6f7332fd09d3cf80374d00f38829f40ff8088b32f7067cfd44cf774d792f5b23bd14065c470d033fdea655657d6cbaa6e80af6459f6bf939393f1789c57acf8340fb6a3a3a39733d0e6fc930991133d833f17e1cfc7444f0ecc3ee93ffe71959f15be007f3eeffff202f0f865fabf320099f422fc4533c6017ef862e33f8a5f26fe053f9b5ee8fa03e10b8f3fae29f34b8f3f1dfe687ac9f94f317e881f76405dfff3790130e3ee9f7fbcd0bfd907e1f452f3ef78c63fc9caf8fbe65fc43fe130cfe9cfc4fc5b51400dfee8f2435d7fb5f9e5eb2f6ef8eaf3ff19e08fa63f23f143f59f80fee7d50a28eb5f7fabf31f73052837fee6facfe0968bdf6c40b0f985d6bf950d0085f8e76d45d0abafbf64f54fe9fa2ff29ff835f47fd15a04bd74fdc1e3971a7fb1035078fe55e257d75f845f447f117ed401b3fe9e5ba6a0ff739b1075fffbdfcb05302bf64ef879f4a2fb5f31fa2fa93f547ff1e985f557833f371ea88dbf65fc4af5472cbfdcfdb799a95cff61eb9f363faebfd8febf84feeaf2afeefff3f8a5f59f1bff19e05f14006c7ed1f9577dfd3d61872fbbfe52ebff45fcbafaa3a5bfa635edfa8b6fa760ff577bfd2f7dffb97f7e75fd8da69ff1830ee8afffb5d75faef9d7ed91ecfaa3853f73778974fccdf07be07726602ffcb9895f5d7f99fc67abfee01bf17f1ee5cf21fd3d03fa87e93fbefe8db7230101c4f517f300ad3f9e3c295e474f80f8eb1e54e680f27b0fbfe8fcb7d2bc8f5e7cfdc976a0077e9703d2fad720f0f00b3fffd5b45ee3b738d039bfcb016d7e8f75b1fe9d4e19f4eaf587bafe4becff02fb1ff8fa934fbf182122facb0fbec63fd7df680146fbdff0c73ae0609f9de07640f6f9eb167e4f0708d4ffc65aeb8feee3cfedeb3faf0392f3efc4a2ffddf32ff63fb8fc92cf1fb65b0ffc3efdefbaff1bebdfaafebae93be167e8bfc40540f7bf859fbfeadd01b0fe13d87f666f40b4e92f107f04ffb4c11fafbf31f5471b7fa40b8eeb3f3bc1e549b7f35f4ffcd6eb9f791d90dc7f6dd15f1fbfe8fd476dfd8fe0efe3fe431ffa6b77a097f8eb365dd1ffbefbbfaeffbefd8fe1afbfa3d9651c80e347f7df65f6bf91f5377fffa15d7fa3f945ea8f2771559067f2e9a1fe57e6470a90b3a0bfb983bf870d7867fc9e0e10baff99c7f24bdc80aed47f2d0499d38191ccf347e6fed3ec6dda2800acfc42cf3fadee3f04172002dbbf3efd73d18bdd7f8d3611fd2bda595f8fa5175aff0af047eb9fbdff7d5b510dfe080f5c97dfc6df76ff61c67f741411bf53ff3c1d2052ffbb1cf0f0775cff7b1c90d43f1b7fc70b2070ff5beef75f22f557ecf9db56fe00fdc3ef7f2af393030715feeaac9305f0c3cf5fadd43f3c7e587f97e38fdbfd65fdb59c7f63e31f3bea3ffffe4787fbbf5e13d1df72fbb5b500f1de0912d25f5b0f4cf9fa7fc4f6c0a9ffecf84b63f263f5a7e6fe9b8cfee93e00a4fefb1f1e077cf58fc4f33ff3fdff567a3277fca8fe78eb0fab0372fc07083fbafe1dfbf4bf537e7ffd67e31fc9ac3ffdfc96f04775fd8fd5dfdcc36f61cf57eb8fb85d007ffd69e7175dff36f923f43f427f4d6366fe595b83f8b91eacaeffd6d6960ef8cca2ffac6180fcfd2919fdd3d65fdd07803cfcdefa5f60fde5e02f4ff13980ea9ff71650d7fa375f8069f1cf1a73ecffdb1c381270a0f2fc85167ff5fecf68340aeeffbafec7df7fa5b60e2625ffa895bf9dbec11fbdff3cce677fffab3d7e0b7b1b7f94fe9af27ba6bf35fa7cddc5dfa63f6c0766fcebeb9386fe97f2cbe58fd1dfbc1a7fbe22bf7c7ebefe56f9fdfabf2c4bacfc8c2d0044fe2af79f587dbe127f34bdd0fd2ff70d0037bddcfac342ef73406cffd1caef70416efe75f33bf4e714f147afff7c8fe074cb5f63afcb0f8f3ffefeeb41b9ff50fcdbaebfaefa4b40ff2afa3b5a71c049dfa2bfb1fa67fefe675bfc16f676fe88f56f957fb5fec85f7238d0ca1fa3bfe38afe33f865f437afe96f117f4d7e1bfcebeb01facb7060b5fe28f86b0e34e20fe167dc0370de7ff7589d9fd1e92df1b75bd608dfce1f39ff7be49fc11f3bff47dfff179a7ffdfadfe5fcefed7fbb030dfe98fd4fe7affff4c01f547f04f203ebbf7ca6c298fe47de7f2d1b2bf71f2cfa1fcc1f7fff3542ffdbe75fa603e3e5ffbfd1a2ffa43f36769bfef23c30f3bf9cfe73d7bfd5fe67f10be9ef32fe207e71fd5dad3f6a2ef4c06fedde9cb7feece2f91337bf8cfec5c72f34ff47ff0a840cbf2f7ebb07c2fae3e0ef52ff42e20fe58f58ff39cbef1ef89d05681ffcb5df7f85f5ff88fdfc53ee5affe6ae2d4011fd5dfeff1badfc0bf2e9b4b1312ca3bf35fe95fdff4afd315ddd1997dd7f6eeeff1bfe08fde7e96f3eef80f24da4fe88d0ff257fad0088e567ff1e40bb6d6c60f8298847f9b5fdd78effbcfbaf3d7ef4f1b9ffa44ef931fc791fbf43c76b8f9f84d7cd7fedf13374fea1e3b5fb4f3fff503c9abf9803faf1ebe2cffbf83beff10f3f7fcf77fe6beb9f365ebbff878f47f3573dff2107f4fb3fe1111bfefc31f8fc831ad8001bf8efa7d9e7a6103f00ce86af7fdafc91f8db5278fdf8d5f317d4cf5ef27707c45b4d3b7f078a17cbbf38fcaddb2fcc7f8af31fc1eface0b9e953c7b3b367bb4c85cafc85e52f8a47f32fe53f8657d27f9dfcdd7eb581e7f19bb18ee0b757f09cf4294ede46f2bf89e7e5ef34cf76eaf3074fbe8babb5534f455efe15f8ed51047e7b6764f9668e8f9e02b4f3571fafb2feace81703bf6d82ad8d7f0ebe25ff99f9d7c4332230644b3c2b7fc8d91d4a8525fe191f1fcd3fa5584bfcc6e2fab1f26fc1bfec7383773730cfff0d9a7f46edf84f03835831edfcc1f1baf74f58fc3bcd328e953e3baf363ee2e117e7c6e9df4633ffb9f9b38ae7e46f891fd5eb0f36ff8afe73f2b7ac352cf91fd2c0023f6dc1bbf37767e9bf2dff5f8c4a24edfc13c85fd5f51f2b7fdaf31fc6070700e2dbc60a33ff1a0d30f3df860fcddf62fea87f1699bf0b3f38fa3bc38f2cf81703f00bfd6fc347e6bf6efef69a7fedfcf0fd9bbef2cf860f0e00c56f34f1bcfcb7ce1f81f96bc787e56ff3b305fe153f7ed15191f95be2b7b35ad270f2b764ddb1f2e7cffc21348cb57eea008fee5f0ecaff96fc3b25f8b0261cf8a006c0fc6b338efe965973cf86f7e6ef2c6bef66d6fc0bc2df8ac65754df92ff117dd8d3fd8baef1d14df48adf6eeee2f69a7f5de223f79f58fa49ffd8f3372c7fee46e397f91b577fcff017ec785ffe4e3bc87f21fd1b46fe39f0b10d88e143ae9d63fe08c2bbf217e50fc9bf96cf58f9333b635a3d31423fa7f42717daf0cf02f11b597bfdeecbbf0a1ec9dfda32a6868f9a834f3c96f0099ff0a7177f3c70ff133ee1133e1e9ff23fe1137eb878347f7d0e9cf6f8133ee1878cd7cedf94ff099ff0f178347fd5f3dfe300489ff009df297ef0f9e769c08f77371080777601187ec2277ca778f5fc05f5d3e74100ded94008de1502e47cc227bcc7069fbf78fe43faeb6b2004efeac47864c227fc39c87fbc7e87f5db154310ded100e2fb79c06baf3fd5f307c57b22f0e371fd44f1b8fec6e79faf8140bcb50f6271a1f8733ffe51bc7afd8ae2f1fc75b9108407ea5f5f0861783c7f6d0d84e26d0d443b1ecaaf8d1f7cfea078547f61fd565dbffa1a08c40f367f7d0d7861d69eeb099ff20fc4c3fbcf285e75fdea6b20101f5d3ffb3c08c6c7e6af278478cfc3f9513cac1f281e1dbff0f8d7c60f3fff06abbf4b43f1ad0ec43333f0eae31f1dbff0f8d7c6a3f9a75fffa2784b03e1f801e72f8cb7747e303ee50f8887f54f1b8feb278a3fcff96b0f60fed5dd7d4e432b7ead6793fb77e2f185138f1f7e17c27ffcc8fff761ac767c927df4701c8f2fec5ff72178f608c43f7e08c13f79fc1284ff37d2fdc94e81dd03f2375bffe4f103207f8f4f9e82f9fbfc3f0f80fc3d3e598f07cbd84718fce9c713553c3a7f648f307832d410fda7f183cc1f94ff083be53f82cfd0fc6715615d18187f81ff0c84c7ae1fcd1f183e196ab75e43d0cfd7eebee03fcb6a70fe3e5fc3f068fe3fc5f019e8bf40feebe2b397417c32d02ed8fe07b12083c72f863f46f110bab0e7285eb7fff0fc07f99369dbf66711b4faf845f1181c36f5f853fe9e7783fe9b9dc1eb1f064f962c1960caf3c731cc0fe293254b166d68fe6ae393254b166fdaf9ab8e479f5f507ffe2159b2e19a7afe6be3c1f9431b9f2c1962f0f8d5cedf84d7c5a7f9eb7cdbc0f5131dff2709af8a4f960c3174fec0c73ff8fc278c87e0eaf864c9104bf90fc1d5f1c9922186d7ffdaf9ab9bff9aebb70b4bbb78e9caebd7ab8797ae5e3bac1eef1e5cbfb13cbeb4bbf7fae18dead77bd70e6f568ef7f6afdda81cefeeed5fbf71ab02dfbf7cfd66e5786ffff2e1e2f8e2c5fd2b07d76ebef1e6fce812f97678ebdb6f19aeddabd76fdc7ce3addbe670efa000bf79fb4e79f6dee52b570f0bf0ed3b6f97715cbe5ab6551cbe4d4ded5e3928da2a0fbfb3f9c75f5e285f7ff8c5b7367ff393af6dbeffc32f6d3eb8f7d5cd77bfff85cdf77ef0c5f2b3dffdec1be5f70f7fbd5b9efbd777f737ff7cffd2e69f7e75b13c36e77cf8e3af2cdee9f5c18fbe5cbe1b2c61e8e72a1f7d46c7bffde9d7cbf3e945bc744cdf932ff4fafdcfbfb938d7bce87b6a97380943af77bef75af939f94f6dd177f432fed2cfd577f283da270c9d6fb0f419f94efd41be5431745cf8b365e2228c899770e483698bdec95783233fe855e04abcf98c7888975ef4b3e1357dfa9777f6ca77ea076a6fde46796cda212e3a3631d3e7744ce7d1cf7f7bef72f9fac70757cb776a93aea56983de4dcce61ad2e7868bcefffbfb57ca9f291e3aa677131b9d6fae17e1e8736ad38c13c29a971947c607331e8cdf669cd08bce31e7198c39e79f1f1e2cf0c617e32bf94ded55fbdff48de977c2527f10c68c6bc29a18cd98a7cfcd982ce2dca297e91b83317d427d6bda32d7cbf46fd1c656c1bf55f4f196191b2646931f86db5c4bea4f3a97ae0b8d71e22ec618f9b0e0a88eadf978d82adad8227fcd18a7b6e6e3abc417afff0309a69f37"; string test3 = "7801EDDC310D00000803B02508C0BF5B828A3DAD904E920900000000000000000000000000000000000000000000000000000000000000F016000000000000000000000000000000A86BFF03000000000000000000000000000000000000000000000000000000000000000040CF01072DC034"; //$ordered = zlib_encode( //int chunkX) . //int chunkZ) . //$orderedIds . //$orderedData . //$orderedSkyLight . //$orderedLight . //$this->biomeIds . //$biomeColors . //$this->tiles byte[] val = SoapHexBinary.Parse(test).Value; Assert.IsNotNull(val); MemoryStream stream = new MemoryStream(val); if (stream.ReadByte() != 0x78) { throw new InvalidDataException("Incorrect ZLib header. Expected 0x78 0x9C"); } stream.ReadByte(); using (var defStream2 = new DeflateStream(stream, CompressionMode.Decompress, false)) { NbtBinaryReader defStream = new NbtBinaryReader(defStream2, true); ChunkColumn chunk = new ChunkColumn(); chunk.x = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); chunk.z = IPAddress.NetworkToHostOrder(defStream.ReadInt32()); int chunkSize = 16 * 16 * 128; Assert.AreEqual(chunkSize, defStream.Read(chunk.blocks, 0, chunkSize)); Assert.AreEqual(chunkSize / 2, defStream.Read(chunk.metadata.Data, 0, chunkSize / 2)); Assert.AreEqual(chunkSize / 2, defStream.Read(chunk.skylight.Data, 0, chunkSize / 2)); Assert.AreEqual(chunkSize / 2, defStream.Read(chunk.blocklight.Data, 0, chunkSize / 2)); Assert.AreEqual(256, defStream.Read(chunk.biomeId, 0, 256)); byte[] ints = new byte[256 * 4]; Assert.AreEqual(ints.Length, defStream.Read(ints, 0, ints.Length)); int j = 0; for (int i = 0; i < ints.Length; i = i + 4) { chunk.biomeColor[j++] = BitConverter.ToInt32(new[] { ints[i], ints[i + 1], ints[i + 2], ints[i + 3] }, 0); } MemoryStream uncompressed = new MemoryStream(); int b = -1; do { b = defStream2.ReadByte(); if (b != -1) { uncompressed.WriteByte((byte)b); } } while (b != -1); Assert.AreEqual(0, uncompressed.Length); //Assert.AreEqual(83208, uncompressed.Length); Assert.AreEqual(8, chunk.x); Assert.AreEqual(9, chunk.z); byte[] data = chunk.GetBytes(false); Assert.AreEqual(83208, data.Length); // Expected uncompressed length } }
private void HandleChunk(bool cacheEnabled, uint subChunkCount, byte[] chunkData, int cx, int cz, Action <ChunkColumn> callback) { if (cacheEnabled) { Log.Warn($"Unsupported cache enabled!"); } bool gotLight = false; try { using (MemoryStream stream = new MemoryStream(chunkData)) { NbtBinaryReader defStream = new NbtBinaryReader(stream, true); //int count = defStream.ReadByte(); if (subChunkCount < 1) { Log.Warn("Nothing to read"); return; } ChunkColumn chunkColumn = new ChunkColumn(); chunkColumn.IsDirty = true; chunkColumn.X = cx; chunkColumn.Z = cz; for (int s = 0; s < subChunkCount; s++) { var section = chunkColumn.Sections[s] as ChunkSection; int version = defStream.ReadByte(); if (version == 1 || version == 8) { int storageSize = defStream.ReadByte(); if (section == null) { section = new ChunkSection(chunkColumn, s, true, 2); } for (int storage = 0; storage < storageSize; storage++) { int paletteAndFlag = defStream.ReadByte(); bool isRuntime = (paletteAndFlag & 1) != 0; int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096.0f / blocksPerWord); uint[] words = new uint[wordCount]; for (int w = 0; w < wordCount; w++) { int word = defStream.ReadInt32(); words[w] = SwapBytes((uint)word); } uint[] pallete = new uint[0]; if (isRuntime) { int palleteSize = VarInt.ReadSInt32(stream); pallete = new uint[palleteSize]; for (int pi = 0; pi < pallete.Length; pi++) { var ui = (uint)VarInt.ReadSInt32(stream); pallete[pi] = ui; } if (palleteSize == 0) { Log.Warn($"Pallete size is 0"); continue; } } int position = 0; for (int w = 0; w < wordCount; w++) { uint word = words[w]; for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { break; // padding bytes } uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (state >= pallete.Length) { continue; } BlockState translated = GetBlockState(pallete[state]); if (translated != null) { if (translated.Block is Water) { string a = ""; } section.Set(storage, x, y, z, translated); } position++; } if (position >= 4096) { break; } } } } else { if (section == null) { section = new ChunkSection(chunkColumn, s, true, 1); } #region OldFormat byte[] blockIds = new byte[4096]; defStream.Read(blockIds, 0, blockIds.Length); NibbleArray data = new NibbleArray(4096); defStream.Read(data.Data, 0, data.Data.Length); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int idx = (x << 8) + (z << 4) + y; var id = blockIds[idx]; var meta = data[idx]; var ruid = BlockFactory.GetBlockStateID(id, meta); BlockState result = null; if (!_convertedStates.TryGetValue( ruid, out result)) { if (id == 124 || id == 123) { result = BlockFactory.GetBlockState("minecraft:redstone_lamp"); if (id == 124) { result = result.WithProperty("lit", "true"); } } else if (id > 0 && result == null) { var reverseMap = MiNET.Worlds.AnvilWorldProvider.Convert.FirstOrDefault( map => map.Value.Item1 == id); if (reverseMap.Value != null) { id = (byte)reverseMap.Key; } var res = BlockFactory.GetBlockStateID(id, meta); if (AnvilWorldProvider.BlockStateMapper.TryGetValue(res, out var res2)) { var t = BlockFactory.GetBlockState(res2); t = TranslateBlockState(t, id, meta); result = t; } else { Log.Info($"Did not find anvil statemap: {result.Name}"); result = TranslateBlockState( BlockFactory.GetBlockState(res), id, meta); } } if (result == null) { var results = BlockFactory.RuntimeIdTable.Where(xx => xx.Id == id) .ToArray(); if (results.Length > 0) { var first = results.FirstOrDefault(xx => xx.Data == meta); if (first == default) { first = results[0]; } result = TranslateBlockState( BlockFactory.GetBlockState((uint)first.RuntimeId), id, meta); } } if (result == null) { result = new BlockState() { Name = $"{id}:{meta.ToString()}", Model = BlockFactory.UnknownBlockModel, Block = new Block(0) { } }; Log.Info($"Unknown block: {id}:{meta}"); } if (result != null) { _convertedStates.TryAdd(ruid, result); } } if (result != null) { section.Set(x, y, z, result); } else { Log.Info($"Unknown block: {id}:{meta}"); } } } } #endregion } if (UseAlexChunks) { // Log.Info($"Alex chunk!"); var rawSky = new API.Utils.NibbleArray(4096); defStream.Read(rawSky.Data, 0, rawSky.Data.Length); var rawBlock = new API.Utils.NibbleArray(4096); defStream.Read(rawBlock.Data, 0, rawBlock.Data.Length); for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { var peIndex = (x * 256) + (z * 16) + y; var sky = rawSky[peIndex]; var block = rawBlock[peIndex]; var idx = y << 8 | z << 4 | x; section.SkyLight[idx] = sky; section.BlockLight[idx] = block; } } } gotLight = true; } section.RemoveInvalidBlocks(); section.IsDirty = true; //Make sure the section is saved. chunkColumn.Sections[s] = section; } /* byte[] ba = new byte[512]; * if (defStream.Read(ba, 0, 256 * 2) != 256 * 2) Log.Error($"Out of data height"); * * Buffer.BlockCopy(ba, 0, chunkColumn.Height, 0, 512);*/ int[] biomeIds = new int[256]; for (int i = 0; i < biomeIds.Length; i++) { biomeIds[i] = defStream.ReadByte(); } chunkColumn.BiomeId = biomeIds; if (stream.Position >= stream.Length - 1) { callback?.Invoke(chunkColumn); return; } int borderBlock = VarInt.ReadSInt32(stream); if (borderBlock > 0) { byte[] buf = new byte[borderBlock]; int len = defStream.Read(buf, 0, borderBlock); } if (stream.Position < stream.Length - 1) { int loop = 0; while (stream.Position < stream.Length - 1) { try { NbtFile file = new NbtFile() { BigEndian = false, UseVarInt = true }; file.LoadFromStream(stream, NbtCompression.None); if (file.RootTag.Name == "alex") { NbtCompound alexCompound = (NbtCompound)file.RootTag; for (int ci = 0; ci < subChunkCount; ci++) { var section = (ChunkSection)chunkColumn.Sections[ci]; var rawSky = new API.Utils.NibbleArray(4096); if (alexCompound.TryGet($"skylight-{ci}", out NbtByteArray skyData)) { rawSky.Data = skyData.Value; } //defStream.Read(rawSky.Data, 0, rawSky.Data.Length); var rawBlock = new API.Utils.NibbleArray(4096); if (alexCompound.TryGet($"blocklight-{ci}", out NbtByteArray blockData)) { rawBlock.Data = blockData.Value; } for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { var peIndex = (x * 256) + (z * 16) + y; var sky = rawSky[peIndex]; var block = rawBlock[peIndex]; var idx = y << 8 | z << 4 | x; section.SkyLight[idx] = sky; section.BlockLight[idx] = block; } } } chunkColumn.Sections[ci] = section; } gotLight = true; } if (stream.Position < stream.Length - 1) { // pre = stream.ReadByte(); } } catch (Exception ex) { // Log.Warn(ex, $"Reading chunk extra data (Loop={loop})"); } loop++; } } if (stream.Position < stream.Length - 1) { Log.Warn( $"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}"); } if (gotLight) { chunkColumn.SkyLightDirty = false; chunkColumn.BlockLightDirty = false; } chunkColumn.CalculateHeight(!gotLight && ClientSideLighting); //Done processing this chunk, send to world callback?.Invoke(chunkColumn); } } catch (Exception ex) { Log.Error($"Exception in chunk loading: {ex.ToString()}"); } finally { } }
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); } }
internal override bool ReadTag(NbtBinaryReader readStream) { int length = readStream.ReadInt32(); if (length < 0) { throw new NbtFormatException("Negative length given in TAG_Int_Array"); } if (readStream.Selector != null && !readStream.Selector(this)) { readStream.Skip(length * sizeof(int)); return false; } Value = new int[length]; for (int i = 0; i < length; i++) { Value[i] = readStream.ReadInt32(); } return true; }