10

客户端-服务端三方时序

End-to-End · 数据可见性

完整链路 + 服务端可见 vs 不可见数据 · 消息体结构构造与校验位置

📡 端到端时序 · 数据可见性图例: 服务端可见 (元数据 + 密文) 服务端不可见 (明文 + 密钥) 服务端持久化 (收件箱) ClientA (Alice 设备) Server (邮箱) ClientB (Bob 设备) ▶ Phase 1: Alice 本地加密 (服务端 不可见) 🔒 仅 Alice 设备可见 ① plaintext = "Hello Bob" ② SK = ChainKey 派生 → MK_n ③ ciphertext = AES-GCM(plain, MK_n) ④ MAC = HMAC(MK_n, ciphertext) ▶ Phase 2: Alice 上行包装为消息体 POST /msg 📤 网络消息 (服务端可见): { sender_id, receiver_id, message: { ratchet_key, chain_index, ciphertext, mac } } ▶ Phase 3: Server 解析头部 + 入收件箱 服务端逻辑 (能看到的部分): • 解析 receiver_id = "bob" • 落 Bob 收件箱 (含 ciphertext) • 等待 Bob 拉取或推送 ⚠ 服务端 看不到 plaintext / MK / 任何明文 ▶ Phase 4: Server 投递 (Bob 在线时主动推 / 不在线时等拉) deliver 📥 Bob 收到原始消息体 { ratchet_key, chain_index, ciphertext, mac } ▶ Phase 5: Bob 本地解密 (服务端 不可见) 🔒 仅 Bob 设备可见 ① 检查 ratchet_key 是否变化 → DH flip? ② 用 chain_index 推进 RecvChain → MK_n ③ 校验 MAC = HMAC(MK_n, ciphertext)? ④ plaintext = AES-GCM⁻¹(ciphertext, MK_n) ▶ Phase 6: Bob 发"已送达" ACK (服务端可见, Alice 收到通知) { msg_id, status: "delivered" } 推送 delivered 给 Alice 📊 数据可见性总表 (谁能看到什么) 数据项 Alice 设备 Server Bob 设备 说明 plaintext (明文) ✓ 写入 ✗ 永不 ✓ 解出 端到端核心 MK / ChainKey / RootKey ✓ 内存 ✗ 永不 ✓ 内存 仅客户端推导 ciphertext + MAC ✓ 生成 ✓ 转发/落库 ✓ 校验+解 业务消息载荷 ratchet_key (公钥) ✓ 嵌入 ✓ 中继 ✓ 提取 公开 (X25519 公钥) sender_id / receiver_id ✓ 已知 ✓ 路由依据 ✓ 已知 服务端无法不感知
客户端

消息体构造

  • • 明文加密 → ciphertext
  • • 计算 MAC = HMAC(MK_n, ciphertext)
  • • 包装 { ratchet_key, chain_index, ciphertext, mac }
  • • 添加 sender_id / receiver_id 后上传
服务端

不可信邮箱角色

  • • 路由 + 存储 + 投递 ACK
  • • 解析 sender_id / receiver_id (元数据可见)
  • • 不解析 / 不修改 ciphertext + mac
  • • 离线则落收件箱, 上线时推送
客户端

消息体校验

  • • 用 chain_index 找/推 MK_n
  • • 优先校验 MAC, 防 MIMT
  • • MAC 通过才执行 AES 解密
  • • 失败时丢弃, 不暴露错误细节
vodozemac

实际 Message 结构

  • version: u8 — 协议版本
  • ratchet_key: Curve25519PublicKey
  • chain_index: u64
  • ciphertext: Vec<u8> + mac: MessageMac
💡 一句话理解: 端到端加密的"端"指的是 密钥与明文都不离开客户端—— 服务端的角色是"忠实的不可信邮差", 它必须知道收发方 ID 才能路由, 但永远看不到内容。 这就是为什么即使 Signal 服务器被攻陷或被传唤, 攻击者也只能拿到密文堆和元数据 — 解不开任何一条消息。

📚 基础知识速查 · Reference

不熟悉以下底层概念? 这里是 30 秒回顾。

算法AES-256-GCM

当前最常用的 AEAD 算法。MK 派生出 enc_key + auth_key + iv 三件套, 给 GCM 同时做加密和认证。

(ct, tag) = AES-GCM-Enc(key, iv, pt, AD)

数据MessageMac

vodozemac 中的 MAC 类型, 通常是 HMAC-SHA256 截断到 8 / 16 字节, 在带宽和安全性之间权衡。

pub struct MessageMac([u8; 8]);

概念端到端加密 (E2EE)

加密发生在端点 (客户端), 中间任何节点 (含服务端) 都看不到明文。E2EE 的"端"指的是密钥不离开设备。

vs TLS (传输层加密) — 服务端能解

概念元数据 (Metadata)

sender_id / receiver_id / timestamp 等。E2EE 通常不保护元数据, 这是协议的局限 (Sealed Sender 等扩展是缓解方案)。

受保护: 内容 ✓ · 不保护: 关系图 ✗