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> /// Deserilizes an MTProtoHelper object from a stream /// </summary> /// <param name="reader">The stream containing the raw MTProtoHelper data</param> public static MTProtoHelper Deserialize(BinaryReader reader) { ServerAuthentication AuthInfo = null; if (BoolUtil.Deserialize(reader)) { byte[] AuthInfoKey = null; if (BoolUtil.Deserialize(reader)) { AuthInfoKey = BytesUtil.Deserialize(reader); } AuthInfo = new ServerAuthentication() { AuthKey = new AuthKey(AuthInfoKey), TimeOffset = IntegerUtil.Deserialize(reader) }; } return(new MTProtoHelper(AuthInfo)); }
/// <summary> /// Deserilizes a Session object from a stream /// </summary> /// <param name="reader">The stream containing the raw Session data</param> public static Session Deserialize(string FileName, BinaryReader reader) { Network.MTProtoHelper Helper = null; if (BoolUtil.Deserialize(reader)) { Helper = MTProtoHelper.Deserialize(BytesUtil.Deserialize(reader)); } TLObject TLUser = null; if (BoolUtil.Deserialize(reader)) { TLUser = TLObject.Deserialize(reader); } var SessionExpires = IntegerUtil.Deserialize(reader); DataCenter DataCenter = null; if (BoolUtil.Deserialize(reader)) { DataCenter = DataCenter.Deserialize(BytesUtil.Deserialize(reader)); } var session = new Session(FileName) { Helper = Helper, TLUser = TLUser, SessionExpires = SessionExpires, DataCenter = DataCenter }; PeerManager.Deserialize(reader).ToList().ForEach(x => session.KnownPeers.AddOrUpdatePeer(x.AsTLObject())); return(session); }
private static TLObject ParseRPCResult(BinaryReader reader) { try { ulong LocalMsgID = reader.ReadUInt64(); uint RPCCode = reader.ReadUInt32(); var RawObject = JObject.FromObject(new { _ = "rpc_result", req_msg_id = LocalMsgID }); if (!Enum.IsDefined(typeof(RPCCodes), RPCCode)) { reader.BaseStream.Position -= 4; RawObject["result"] = TLObject.Deserialize(reader); return(new TLObject(RawObject)); } switch ((RPCCodes)RPCCode) { case RPCCodes.rpc_error: RawObject["result"] = JObject.FromObject(new { _ = "rpc_error", error_code = IntegerUtil.Deserialize(reader), error_message = StringUtil.Read(reader) }); //if (errorMessage.StartsWith("FLOOD_WAIT_")) //{ // var resultString = Regex.Match(errorMessage, @"\d+").Value; // var seconds = int.Parse(resultString); // throw new FloodException(TimeSpan.FromSeconds(seconds)); //} //else if (errorMessage.StartsWith("PHONE_MIGRATE_")) //{ // var resultString = Regex.Match(errorMessage, @"\d+").Value; // var dcIdx = int.Parse(resultString); // throw new PhoneMigrationException(dcIdx); //} //else if (errorMessage.StartsWith("FILE_MIGRATE_")) //{ // var resultString = Regex.Match(errorMessage, @"\d+").Value; // var dcIdx = int.Parse(resultString); // throw new FileMigrationException(dcIdx); //} //else if (errorMessage.StartsWith("USER_MIGRATE_")) //{ // var resultString = Regex.Match(errorMessage, @"\d+").Value; // var dcIdx = int.Parse(resultString); // throw new UserMigrationException(dcIdx); //} //else if (errorMessage.StartsWith("NETWORK_MIGRATE_")) //{ // var resultString = Regex.Match(errorMessage, @"\d+").Value; // var dcIdx = int.Parse(resultString); // throw new NetworkMigrationException(dcIdx); //} //else if (errorMessage == "AUTH_RESTART") //{ // throw new AuthRestartException("The session is already logged in but is trying to log in again"); //} //else if (errorMessage == "PHONE_CODE_INVALID") //{ // throw new InvalidPhoneCodeException("The numeric code used to authenticate does not match the numeric code sent by SMS/Telegram"); //} //else if (errorMessage == "SESSION_PASSWORD_NEEDED") //{ // throw new CloudPasswordNeededException("This Account has Cloud Password !"); //} //else //{ // throw new InvalidOperationException(errorMessage); //} break; case RPCCodes.gzip_packed: RawObject["result"] = JObject.Parse(ParseGZipPacked(reader).ToString()); break; default: reader.BaseStream.Position -= 4; RawObject["result"] = JObject.Parse(TLObject.Deserialize(reader).ToString()); break; } return(new TLObject(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()) }))); }