这篇关于telegram,MTProto 端到端加密的文章是为高级用户准备的。如果您想从不那么令人生畏的来源了解更多关于秘密聊天的信息,请参阅我们的一般常见问题解答。
请注意,从 4.6 版开始,主要的 Telegram 客户端正在使用MTProto 2.0。MTProto v.1.0 已弃用,目前正在逐步淘汰。
TG秘密聊天是一对一的聊天,其中消息使用仅由聊天参与者持有的密钥进行加密。请注意,这些端到端加密秘密聊天的架构与用于云聊天的架构不同:
本文介绍了 MTProto 协议2.0版本中的端到端加密层。与 1.0 版(此处描述以供参考)的主要区别如下:
使用 SHA-256 代替 SHA-1;
填充字节参与 msg_key 的计算;
msg_key 不仅取决于要加密的消息,还取决于秘密聊天密钥的一部分;
使用 12..1024 填充字节代替 v.1.0 中的 0..15 填充字节。
密钥生成:密钥是使用Diffie-Hellman 协议生成的。让我们考虑以下场景:用户A想与用户B发起端到端加密通信。
发送请求
电报用户A执行messages.getDhConfig以获得 Diffie-Hellman 参数:素数p和高阶元素g。
在每个新的密钥生成过程之前执行此方法至关重要。将参数的值与版本一起缓存是有意义的,以避免每次都必须接收所有值。如果客户端上存储的版本仍然是最新的,则服务器将返回构造函数messages.dhConfigNotModified。
纸飞机客户端需要检查p是否是一个安全的 2048 位素数(意味着p和(p-1)/2都是素数,并且 2^2047 < p < 2^2048),并且g生成一个循环子群素数阶(p-1)/2,即是二次余数mod p。由于g总是等于 2、3、4、5、6 或 7,这很容易使用二次互易定律完成,在p mod 4g上产生一个简单的条件——即p mod 8 = 7 for g = 2;p mod 3 = 2对于g = 3 ; g = 4没有额外条件;p mod 5 = 1 或 4对于g = 5 ; p mod 24 = 19 或 23对于g = 6;对于g = 7,p mod 7 = 3、5 或 6。在客户端检查g和p之后,缓存结果是有意义的,以避免将来重复冗长的计算。此缓存可能与用于生成授权密钥的缓存共享。
如果客户端需要额外的随机数生成器熵,它可以传递random_length参数(random_length> 0),以便服务器生成自己的随机序列random适当的长度。 重要提示:以原始形式使用服务器的随机序列可能是不安全的,它必须与客户端序列结合使用。
客户端A计算一个 2048 位数字a(使用足够的熵或服务器的随机数;见上文)并在传入 后执行messages.requestEncryptiong_a := pow(g, a) mod dh_prime。
用户B使用聊天构造函数encryptedChatRequested接收所有关联授权密钥(所有授权设备)的更新updateEncryption。必须向用户显示有关用户A 的基本信息,并且必须提示用户接受或拒绝请求。
两个客户端都要检查g、g_a和g_b是否大于一且小于p-1。我们建议检查g_a和g_b是否也在2^{2048-64}和p - 2^{2048-64}之间。
接受请求
飞机在用户B在客户端界面中确认创建与A的秘密聊天后,客户端B还会收到 Diffie-Hellman 方法的最新配置参数。此后,它使用类似于 a 的规则生成一个随机的 2048 位数字b。
从带有encryptedChatRequested的更新中接收到g_a后,它可以立即生成最终的共享密钥:。如果密钥长度 < 256 字节,则添加几个前导零字节作为填充 - 使密钥长度正好为 256 字节。它的指纹key_fingerprint等于 SHA1(密钥)的最后 64 位。key = (pow(g_a, b) mod dh_prime)
注意 1:在这种特殊情况下,此处使用 SHA1,甚至用于 MTProto 2.0 秘密聊天。
注意 2:此指纹用作密钥交换过程的健全性检查,以在开发客户端软件时检测错误 - 它不连接到客户端上使用的密钥可视化,作为秘密聊天中的外部身份验证的手段。客户端上的密钥可视化是使用 SHA1(初始密钥)的前 128 位生成的,然后是 SHA256 的前 160 位(秘密聊天更新到第 46 层时使用的密钥)。
客户端B在传递完messages.acceptEncryptiong_b := pow(g, b) mod dh_prime和key_fingerprint后执行。
对于客户端B 的所有授权设备(当前设备除外),updateEncryption更新是使用构造函数encryptedChatDiscarded发送的。此后,唯一能够访问秘密聊天的设备是设备B,它调用了messages.acceptEncryption。
用户A将收到带有构造函数encryptedChat的updateEncryption更新,用于启动聊天的授权密钥。
使用更新中的g_b,客户端A还可以计算共享密钥key = (pow(g_b, a) mod dh_prime)。如果密钥长度 < 256 字节,则添加几个前导零字节作为填充 - 使密钥长度正好为 256 字节。如果接收到的密钥的指纹与传递给encryptedChat的指纹相同,则可以发送和处理传入消息。否则,必须执行messages.discardEncryption并通知用户。
完美的前向保密
为了保证过去的通信安全,一旦使用密钥对超过 100 条消息进行解密和加密,或已使用超过一周,官方 Telegram 客户端将启动重新加密,前提是该密钥已用于加密至少一条消息。旧密钥随后会被安全丢弃且无法重建,即使访问当前正在使用的新密钥也是如此。