Ejemplo n.º 1
0
        /// <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())
            })));
        }