Telegram 电报 MTProto 移动协议
请随时查看我们的技术倾斜常见问题解答。客户端开发人员必须遵守安全指南。
相关文章
- 移动协议:详细说明
- 创建授权密钥
- 创建授权密钥:示例
- 移动协议:服务消息
- 移动协议:关于消息的服务消息
- 二进制数据序列化
- 语言
- MTProto TL-模式
- 端到端加密,秘密聊天
- 端到端 TL 模式
- 客户端软件开发人员的安全指南
此页面处理用于云聊天的基本 MTProto 加密层(服务器-客户端加密)。也可以看看:
- 秘密聊天,端到端加密
- 端到端加密语音通话
一般说明
该协议旨在从移动设备上运行的应用程序访问服务器 API。必须强调的是,Web 浏览器不是这样的应用程序。
该协议被细分为三个几乎独立的组件:
- 高级组件(API 查询语言):定义 API 查询和响应转换为二进制消息的方法。
- 加密(授权)层:定义消息在通过传输协议传输之前加密的方法。
- 传输组件:定义客户端和服务器通过其他一些现有的网络协议(例如HTTP、HTTPS、WS(plain websockets)、WSS(websockets over HTTPS)、TCP、UDP)传输消息的方法。
从 4.6 版开始,主要的 Telegram 客户端正在使用MTProto 2.0,如本文所述。MTProto v1.0(此处描述以供参考)已被弃用,目前正在逐步淘汰。
简要组件摘要
高级组件(RPC 查询语言/API)
从高级组件的角度来看,客户端和服务器在会话中交换消息。会话附加到客户端设备(更准确地说是应用程序)而不是特定的 websocket/http/https/tcp 连接。此外,每个会话都附加到一个用户密钥 ID,通过它实际完成授权。
与服务器的多个连接可能是打开的;消息可以通过任何连接向任一方向发送(对查询的响应不一定通过承载原始查询的同一连接返回,尽管大多数情况下是这种情况;但是,在任何情况下,消息都不能通过属于不同会话的连接返回)。使用 UDP 协议时,响应可能会由与发送查询的 IP 地址不同的 IP 地址返回。
有几种类型的消息:
- RPC 调用(客户端到服务器):调用 API 方法
- RPC 响应(服务器到客户端):RPC 调用的结果
- 消息收到确认(或者更确切地说,一组消息的状态通知)
- 消息状态查询
- 多部分消息或容器(包含多个消息的容器;例如,需要通过 HTTP 连接一次发送多个 RPC 调用;另外,容器可能支持 gzip)。
从较低级别协议的角度来看,消息是沿 4 或 16 字节边界对齐的二进制数据流。消息中的前几个字段是固定的,由加密/授权系统使用。
每条消息,无论是单独的还是容器内的,都由消息标识符(64 位,见下文)、会话中的消息序列号(32 位)、长度(消息体的字节数;32 位)和一个主体(任何大小,是 4 个字节的倍数)。另外,当发送一个容器或单个消息时,在顶部添加一个内部头(见下文),然后对整个消息进行加密,并在消息顶部放置一个外部头(一个 64 位密钥标识符和一个 128 位的消息密钥)。
消息体通常由 32 位消息类型和后跟类型相关参数组成。特别是,每个 RPC 函数都有对应的消息类型。有关更多详细信息,请参阅二进制数据序列化、移动协议:服务消息。
所有数字都写为小端。但是,RSA 和 DH 中使用的非常大的数字(2048 位)以大端格式编写,因为 OpenSSL 库就是这样做的。
授权和加密
在使用传输协议通过网络传输消息(或多部分消息)之前,它会以某种方式进行加密,并在消息的顶部添加一个外部标头,即:64 位密钥标识符(唯一标识服务器和用户的授权密钥)和 128 位消息密钥. 用户密钥与消息密钥一起定义了一个实际的 256 位密钥,它使用 AES-256 加密来加密消息。请注意,要加密的消息的初始部分包含可变数据(会话、消息 ID、序列号、服务器 salt),这些数据显然会影响消息密钥(以及 AES 密钥和 iv)。消息密钥定义为消息体(包括会话、消息 ID 等)的 SHA256 的中间 128 位,包括填充字节,前面加上取自授权密钥的 32 个字节。多部分消息被加密为单个消息。
有关技术规范,请参阅移动协议:详细说明
客户端应用程序必须做的第一件事是创建一个授权密钥,该密钥通常在首次运行时生成并且几乎不会更改。
该协议的主要缺点是入侵者被动地截获消息,然后以某种方式盗用授权密钥(例如,通过窃取设备)将能够在事后解密所有截获的消息。这可能不是什么大问题(通过窃取设备,人们还可以访问缓存在设备上的所有信息,而无需解密任何内容);但是,可以采取以下步骤来克服这一弱点:
- 使用 Diffie-Hellman 协议生成的会话密钥,并与授权和消息密钥结合使用以选择 AES 参数。要创建这些,客户端在创建新会话后必须做的第一件事是向服务器发送一个特殊的 RPC 查询(“生成会话密钥”),服务器将响应该查询,然后会话中的所有后续消息都使用加密会话密钥也是如此。
- 使用(文本)密码保护存储在客户端设备上的密钥;此密码永远不会存储在内存中,而是由用户在启动应用程序时或更频繁地输入(取决于应用程序设置)。
- 存储(缓存)在用户设备上的数据也可以通过使用授权密钥进行加密来保护,而授权密钥又将受到密码保护。然后,甚至需要密码才能访问该数据。
时间同步
如果客户端时间与服务器时间相差很大,则服务器可能会开始忽略客户端消息,反之亦然,因为消息标识符无效(与创建时间密切相关)。在这种情况下,服务器会向客户端发送一条特殊的消息,其中包含正确的时间和一定的 128 位 salt(客户端在特殊的 RPC 同步请求中明确提供或等于从客户端收到的最新消息的密钥)在当前会话期间)。此消息可能是包含其他消息的容器中的第一个消息(如果时间差异很大但尚未导致客户端的消息被忽略)。
收到这样的消息或持有它的容器后,客户端首先执行时间同步(实际上,只是存储服务器时间与自己的时间之间的差异,以便能够计算未来的“正确”时间),然后验证消息标识符的正确性。
如果忽略了更正,客户端将不得不生成一个新会话以确保消息标识符的单调性。
MTProto 传输
在使用选定的传输协议发送之前,必须将有效负载包装在由适当的 MTProto 传输协议定义的辅助协议头中。
- 简略
- 中间的
- 填充中间体
- 满的
服务器通过标头识别这些不同的协议(并将它们与 HTTP 区分开来)。此外,还可以使用以下传输功能:
- 快速确认
- 传输错误
- 传输混淆
这些协议的示例实现可以在tdlib和MadelineProto中看到。
运输
允许将加密容器与外部标头(以下称为Payload)一起从客户端传送到服务器并返回。定义了多种传输协议:
- TCP
- 网络套接字
- 基于 HTTPS 的 Websocket
- HTTP
- HTTPS
- UDP
(我们将只研究前五种类型。)
回顾
回顾一下,使用ISO/OSI 堆栈作为比较:
- 第 7 层(应用程序):高级 RPC API
- 第 6 层(演示):类型语言
- 第 5 层(会话):MTProto 会话
- 第 4 层(传输):
- 4.3:MTProto传输协议
- 4.2:MTProto 混淆(可选)
- 4.1:传输协议
- 第 3 层(网络):IP
- 第 2 层(数据链路):MAC/LLC
- 第 1 层(物理):IEEE 802.3、IEEE 802.11 等…