private static TLObject ParseMessageContainer(BinaryReader reader) { try { var RawObject = new JArray(); var MessageCount = IntegerUtil.Deserialize(reader); for (int i = 0; i < MessageCount; i++) { RawObject.Add(new JObject { ["msg_id"] = LongUtil.Deserialize(reader), ["seqno"] = IntegerUtil.Deserialize(reader), ["bytes"] = IntegerUtil.Deserialize(reader), ["body"] = TLObject.Deserialize(reader) }); } return(new TLObject(JObject.FromObject(new { _ = "msg_container", messages = RawObject }))); } catch { return(null); } }
/// <summary> /// Inverse of <see cref="EncryptMessageData"/> for incoming server messages. /// </summary> public TLObject DecryptMessageData(byte[] body, bool client = false) { if (body.Length < 8) { throw new Exception("Cannot decrypt a message of 8 bytes."); } using (var memory = new MemoryStream(body)) using (var reader = new BinaryReader(memory)) using (var sha = new SHA256Managed()) { var serverKeyID = reader.ReadUInt64(); if (serverKeyID != AuthInfo.AuthKey.KeyID) { throw new Exception($"Server replied with an invalid auth key: {serverKeyID}"); } var MessageKey = reader.ReadBytes(16); (var AES_Key, var AES_ID) = CalcKey(AuthInfo.AuthKey.Key, MessageKey, client); body = AES.DecryptIGE(reader.ReadBytes(body.Length - 24), AES_Key, AES_ID); // https://core.telegram.org/mtproto/security_guidelines // Sections "checking sha256 hash" and "message length" var SHAHash = sha.ComputeHash(AuthInfo.AuthKey.Key .Skip(client ? 88 : 96).Take(32) .Concat(body) .ToArray()); var SHASlice = SHAHash.Skip(8).Take(16); if (!SHASlice.SequenceEqual(MessageKey)) { throw new Exception("The message key could not be validated."); } } TLObject obj = null; byte[] RawObject = null; var remote_msg_id = -1L; var remote_sequence = -1L; using (var memory = new MemoryStream(body)) using (var reader = new BinaryReader(memory)) { // The salt could be 0 if we are starting anew and haven't received one yet if (Salt != LongUtil.Deserialize(reader) && Salt != 0) { throw new Exception("The salt could not be validated"); } if (ID != LongUtil.Deserialize(reader)) { throw new Exception("The session ID could not be validated"); } remote_msg_id = LongUtil.Deserialize(reader); // ToDo: Check sequence_number remote_sequence = IntegerUtil.Deserialize(reader); RawObject = reader.ReadBytes(IntegerUtil.Deserialize(reader)); obj = TLObject.Deserialize(RawObject); } return(new TLObject(JToken.FromObject(new { _ = "Message", msg_id = remote_msg_id, seqno = remote_sequence, bytes = RawObject, body = JToken.Parse(obj.ToString()) }))); }