TG WS Proxy代码剖析MTProto混淆握手全解读——dd/ee密钥与64字节init包的AES-CTR解密TG WS Proxy 是一款运行在本地的 MTProto 代理服务器把 Telegram Desktop 的流量改走 WebSocket 通道从而绕开部分加载卡顿。本文带你拆解它的握手代码dd/ee两种密钥的来历、64 字节 init 包的逐段结构以及代理如何用 AES-CTR 解密并验证客户端的完整流程。 TG WS Proxy 是什么本地 MTProto 代理的架构一句话概括客户端连上本地代理后代理拦截 MTProto 混淆连接把数据解密→重新加密后转发给 Telegram 的 WebSocketkws*.web.telegram.orgWebSocket 不通时再依次回退到 Cloudflare 代理、CF Worker 或直接 TCP 转发。整个握手与加解密的入口都在 proxy/tg_ws_proxy.py 中每连接一条客户端就派生一个异步任务执行_handle_client依次完成读 init 包 → 验证握手 → 建加密上下文 → 重加密桥接四步。️ dd 与 ee两种密钥从哪里来服务启动时代理会生成两条连接链接见_run前缀链接格式含义ddsecretdd32位hex标准 MTProto 混淆直连eesecretee32位hex域名的hexFake TLS 伪装 MTProto 混淆两者共用同一个 32 位十六进制16 字节的secret区别只在握手的第一段长什么样。dd 密钥裸 MTProto 混淆连接开启端点收到第一个字节后如果不是 TLS 记录头就直接按 MTProto 混淆模式读满 64 字节 init 包_read_client_init。这是 Telegram 官方 MTProto 代理的标准形态。ee 密钥Fake TLS 伪装握手配置了--fake-tls-domain后客户端会先发一个伪装的 TLS ClientHello验证端用HMAC-SHA256(secret, 抹零random后的ClientHello)的前 28 字节比对client_random末 4 字节还原出带时间戳±120 秒容差见verify_client_hello回应一个构造好的 ServerHelloserver_random也是 HMAC 派生见build_server_hello之后的 64 字节 init 包被包在 TLS 应用数据记录0x17里传输见 fake_tls.py。这样在链路上抓包看到的就是TLS 连接 加密数据更难被特征识别。验证不通过则直接回 301 跳转把非 TG 流量踢到伪装域名。 64 字节 init 包的结构拆解所有偏移常量集中在 proxy/utils.py一次看全偏移长度内容0–78随机填充8–3932prekey本次连接随机的预密钥40–5516ivAES-CTR 的 16 字节初始向量56–594协议标签解密后才可见60–612DC 索引小端有符号负数 媒体 DC62–632随机填充三个协议标签同样定义在 proxy/utils.pyef ef ef ef0xEFEFEFEF— abridged 协议ee ee ee ee0xEEEEEEEE— intermediate 协议dd dd dd dd0xDDDDDDDD— padded intermediate 协议注意56–61 这段在线路上是密文必须用 AES-CTR 解开才能看到标签和 DC。 AES-CTR 解密代理如何验证客户端核心逻辑只有几十行全部在_try_handshake取材料prekey init[8:40]iv init[40:56]推密钥key SHA256(prekey secret)——每次连接 prekey 都是随机 32 字节密钥永不上链路且必须持共享 secret 才能算出全量解密用AES-128-CTR(key, iv)解整 64 字节验证标签明文字节 56:60 必须命中三个协议标签之一否则判定错误密钥或错误协议丢弃连接读 DC字节 60:62 小端取有符号整数绝对值即数据中心编号负号表示媒体 DC。AES-CTR 的加密与解密是同一操作对称密钥流所以代码里解密器直接复用了加密器proxy/_aes.py。依赖兜底没有 cryptography 也能跑proxy/_aes.py 是个垫片桌面/Docker 环境优先用cryptography库路由器、嵌入式这类装不了 Python 包的环境自动回退到 ctypes 直调系统 OpenSSL 的EVP_aes_*_ctr接口第 17–64 行支持 128/192/256 位密钥。 反向密钥与重加密桥握手验证通过后代理还要建四路加密上下文_build_crypto_ctx封装在 bridge.py 的CryptoCtx中方向密钥材料解客户端decSHA256(prekey secret)iv 取[40:56]回客户端enc把prekey‖iv整段字节翻转后再SHA256(前32字节 secret)iv 取翻转后的后 16 字节发 Telegramenc直接用 relay init 的[8:40]/[40:56]无 secret收 Telegramdec同样取 relay init 的[8:56]翻转后拆 3216发往 Telegram 的 relay init 是怎么造的_generate_relay_init生成一包标准 MTProto 混淆init不掺 secret并做了三处防误判过滤首字节避开0xEF协议保留字节前 4 字节避开HEAD/POST/GET/eeee/dddd/TLS 记录头等保留开头字节 4:8 避开全零的00 00 00 00续传标记。最后 8 字节标签 DC的密文是用 AES-CTR手动截取密钥流异或构造出来的保证 Telegram 解开后看到正确的协议标签与 DC 索引。双向重加密bridge_ws_reencryptbridge.py 里的桥接逻辑是全文最点睛的部分两条协程互相对称上行客户端密文 → clt_dec 解密 → tg_enc 加密 → 发往 WS 下行WS 密文 → tg_dec 解密 → clt_enc 加密 → 回客户端即客户端侧dd/ee 密钥域与 Telegram 侧标准混淆域各说各的密码代理在中间当翻译官。配合 MsgSplitter 把连续 TCP 流按 MTProto 包边界切开abridged 按 1/4 字节头长计算intermediate 按 4 字节长度头计算每个包单独成 WebSocket 帧发送避免大包粘包。 核心源码文件导航proxy/tg_ws_proxy.py — 主入口握手验证、密钥链接生成、DC 路由与回退proxy/bridge.py — 四路加密上下文、消息切分、双向重加密桥proxy/_aes.py — AES-CTR 垫片cryptography / OpenSSL 双实现proxy/fake_tls.py — ee 密钥的伪 TLS 验证与应答proxy/utils.py — 握手包偏移与协议标签常量proxy/raw_websocket.py — 自研 WebSocket 客户端含 302 重定向跟随使用文档docs/EN/README.md、docs/EN/FakeTlsNginx.md、docs/EN/CfWorker.md 获取源码git clone https://gitcode.com/gh_mirrors/tg/tg-ws-proxy总结TG WS Proxy 的握手设计可以浓缩成三个要点密钥分层dd走标准混淆ee先过一层 HMAC 伪 TLS 再进混淆抓包特征各不相同密钥不上线AES 密钥永远由随机 prekey 共享 secret经 SHA256 现场推导链路上只暴露可丢弃的随机材料双域重加密代理持有客户端域与 Telegram 域两套独立的 CTR 密钥流逐块解密再加密让两端协议互不感知中间人。读懂这套64 字节 init 包 AES-CTR的握手再去看 Telegram 任何 MTProto 混淆代理的实现都会顺畅许多。创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考