查看: 211|回复: 0

关于 OldChat 加密协议的详细讨论

 荐 [复制链接]

3

主题

2

回帖

54

积分

注册会员

积分
54
QQ
发表于 2026-8-4 10:37:04 | 显示全部楼层 |阅读模式

旧聊(OldChat)的加密逻辑,看似很复杂,实则一点也不简单。我愿称其为 MCL0's TLS,硬生生在 Android 2.3 这样一个完全不支持 TLS 的平台上实现了一个类似 TLS 的加密逻辑。核心就一句话,先用 ECDH 握手商量出密钥,再用这把密钥加密消息和校验。底层用 SpongyCastle 加密库。

握手入口时 /auth/handshake,这一步是明文,只用来交换公钥。客户端先本地生成一对临时的 ECDH 密钥对,把公钥 base64 编码后 POST 给服务端。服务端用加密的东西返回:会话密钥来自双方协商,服务端返回自己的公钥和 session_id。客户端拿到服务端公钥,用 ECDH 算出双方共有的共享密钥,再对共享密钥做 SHA-256 哈希,从而双方得到两个相同的密钥,encKey 给 AES 用,macKey 给 HMAC 用。

session 建立后,请求开始加密。先把请求体 JSON 序列化,然后拿 encKey 用 AES 加密成密文,再对加密文算一个 HMAC,然后 HMAC-SHA256,密钥是 macKey。请求头带 X-Enc:1 表示加密,X-Session:<session_id> 表示用哪一会话;压缩过就再加 X-Enc-Compression:gzip。服务端响应走同样的一套信封。

收到后的解密通讯顺序是固定的。先校验 mac 是否等于 HMAC-SHA256(macKey),不等于就证明被篡改直接丢。过了再用 encKey 做 AES-256-CBC 解密,然后 PKCS7 去填充,最后按 UTF-8 还原成明文 JSON。

WebSocket 实时消息的加密跟 HTTP 是一样的,区别在 URL 上带了 ?token=&session=,或者说最新版也可以用 Head 传入部分参数。服务端推进来一条就是一分加密信封,格式固定 {"iv":..., "data":..., "mac":...},三个字段全 base64。客户端读取线程拿到信封第一步就解密,之后再喂给解析队列。

会话不永久。WebSocket 断连就清的加密密钥,重连前会再走一次 ensureSession()。服务端返回 invalid_session 就直接清掉 session 重试一次,从而重新建立;遇到 401 就先刷新 access_token,刷新失败再回退到重登录。所以这也解释了为啥 OC 最近天天掉登录。

整体链路是闭环的:ECDH 握手 → 派生 encKey 和 macKey → AES 加密 + HMAC 校验进行传输 → WebSocket 也套同一套信封。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注公众号

相关侵权、举报、投诉及建议等,请发 E-mail:admin@discuz.vip

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖
关注公众号
返回顶部