主题
XHIM 端到端加密(E2EE)
1. 这项功能保护什么
XHIM 原生 Core 已实现可由服务器统一开启或关闭的端到端加密。 开启后,消息正文和附件在发送设备上加密,只有会话内 已提交的接收设备可以解密。XHIM Server、PostgreSQL、对象存储、 Push 服务商和普通网络代理都拿不到明文密钥。
具体覆盖:
- 单聊和群聊使用 IETF MLS 1.0(RFC 9420);
- 密码套件为
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519; - 正文、自定义消息载荷和编辑后的正文使用 MLS application message 加密;
- 图片、视频、语音和文件使用每个对象独立随机密钥的 XChaCha20-Poly1305 分块加密,对象存储只保存密文;
- 每个账号设备使用独立 Ed25519 身份钥,设备变化后会重新换钥;
- 群成员和设备名册变化使用 MLS Add/Remove 批量对账,服务端 按会话串行化并发 Commit;
- 身份安全码可通过面对面、电话或其他可信渠道比对, 并把当前对端设备标记为已核验;
- OpenMLS Provider ABI v8 还提供 RFC 9605 SFrame 帧加密变换。 Core 只会把已提交 MLS epoch 派生的通话密钥交给 RTC 适配层。
required 是强制模式。Provider 不可用、群状态缺失、身份钥异常变化、 附件缺少加密描述、AAD 篡改、重放、epoch 不匹配或 RTC Provider 不支持 SFrame 时都会直接失败,不会偷偷改用明文。
2. 开启方式
部署管理员在服务端配置:
dotenv
XHIM_E2EE_ENABLED=truetrue:服务器要求普通聊天消息使用 MLS,明文消息会返回e2ee_required;false:服务器关闭 E2EE 控制面,MLS 信封会返回e2ee_disabled;- 修改后重启服务器生效。客户端通过
/v1/sdk/config读取结果, 只能显示状态,没有开启、关闭或降级权限。
iOS 与 macOS 业务页面不需要传入加密选项。Demo 会先读取服务器 策略,再按该策略建立会话:
swift
XHIMClient.connect(
server: "https://im.example.com",
userID: currentUserID,
authentication: .business(account.fetchXHIMCredential),
onConnecting: {
loadingView.show()
},
onConnectSuccess: { client in
loadingView.hide()
account.xhimClient = client
},
onConnectFailure: { error in
loadingView.hide()
account.show(error.message)
}
)需要核对联系人身份时,先显示安全码,确认无误后再标记:
swift
client.getE2EEIdentitySafety(
conversationID: conversationID,
peerUserID: friendUserID
) { result in
switch result {
case .success(let safety):
safetyCodeLabel.text = safety.safetyCode
showVerifyButton(expectedCode: safety.safetyCode)
case .failure(let error):
showError(error.message)
}
}服务器要求 E2EE 时,制品缺少 OpenMLS Provider、SQLCipher 密钥或 E2EE 控制面会直接登录失败,不会回退为明文。
3. 安全码和设备变化
- 安全码绑定当前会话、双方用户和对端已提交的全部 MLS 设备指纹。
- 应用必须展示 Core 返回的
safetyCode或verificationURI, 不得在 UI 层自行重算。 - 点击“已核验”时必须带回用户刚刚看到的安全码。如果期间 新增设备或密钥变化,操作会以
e2ee_identity_changed失败, 不会把新身份误认为已核验。 - 同一设备指纹的信任会持久化;指纹改变后会恢复为未核验。
- 安全码是手工身份核验,不等同于独立的全局 Key Transparency 日志。如果用户从未在可信渠道比对,恶意服务端在首次使用时 替换密钥仍属于剩余风险。
4. 平台支持边界
| 平台 | MLS 消息/附件 | 安全码与设备核验 | 当前说明 |
|---|---|---|---|
| iOS / macOS | 支持 | 支持 | 正式包必须包含 OpenMLS + SQLCipher |
| Android(Java/Kotlin) | 支持 | 支持 | Java 是文档默认接入方式 |
| Windows | 支持 | 支持 | 使用原生 Core 和 .NET Facade |
| HarmonyOS | 支持 | 支持 | 使用原生 Core 和 N-API |
| Electron | 支持 | 支持 | 只在 Main 进程持有密钥,Renderer 通过受限 IPC |
| Flutter | 支持 | 支持 | 依赖 Android/Apple 原生 Core |
| Web 浏览器 / 小程序 | 暂不支持 | 暂不支持 | 尚无审核通过的 OpenMLS WASM/密钥存储实现 |
老 Core 缺少身份核验符号时,各端稳定返回 e2ee_identity_unsupported,不会用空安全码伪装成功。
5. 音视频的准确状态
Core 与 OpenMLS Provider 已实现 RFC 9605 AES_128_GCM_SHA256_128 SFrame 加解密、单调帧计数、重放窗口、 通话代次绑定和成员范围绑定。凭证刷新会复用同一变换实例, 不重置计数器和重放窗口。
不过,仓库目前仍是 RTC Provider 抽象层和合同测试,尚未交付经过 LiveKit、ZEGO 或 WebRTC 真实媒体流验收的 Provider 实现。因此:
- 单聊与全群成员参与的群通话可以获得 MLS 派生的 SFrame 变换;
- 群内部分成员通话暂时返回
sframe_participant_scope_unsupported,因为直接使用全群密钥会让 未入会群成员具有密钥范围; - 任何宣称“音视频已生产级 E2EE”的制品,都必须再通过真实 Provider、真机、网络切换、弱网、录屏和画中画矩阵。
6. 服务端可见范围
text
应用 UI
│ 明文(仅本设备内)
▼
XHIM Core + OpenMLS Provider
│ MLS 密文 / 加密附件
▼
XHIM Server + PostgreSQL + Object Storage服务端仍需要看到路由和权限元数据,包括租户、会话 ID、成员、 发送/接收设备、时间、密文大小、MLS epoch、KeyPackage 和投递状态。 服务端不获得设备私钥、MLS group secret、消息正文、附件内容密钥或 附件明文。Push 只能使用通用占位文案。
7. 企业审计模式
E2EE 与“服务端正文检索/审核/法务导出”不能同时成立。部署方必须 在服务器统一选择:
required:服务端不可见正文,禁用服务端正文搜索、审核和导出;disabled:允许企业在明确告知后运行审计、DLP 和归档。
不存在对用户隐藏的“管理员解密后门”。Business Notification 是另一种 明确的 server_visible=true 业务消息,不得伪装成 E2EE 消息。
8. 发布级别与剩余门禁
当前原生消息/附件 E2EE 已有成员换钥、崩溃恢复、身份安全码、 恶意身份换钥拦截和跨端 Facade 合同。对外准确用语是:
XHIM 原生端提供基于 RFC 9420 MLS、由服务器统一控制的端到端加密, 包含附件密文存储、自动成员换钥与安全码核验。
在以下门禁完成前,不应宣传“所有端完全 E2EE”、“音视频已生产级 E2EE”、“绝对安全”或“已通过顶级密码学认证”:
- 独立密码学审计与修复复验;
- 浏览器/小程序的审核通过 OpenMLS WASM 和安全密钥存储;
- 真实 RTC Provider 的 SFrame 接线和真机互操;
- 独立可审计的 Key Transparency 服务;
- 全销售平台多设备、换机、成员增删、重放、断电恢复和恶意服务端矩阵;
- SBOM、依赖许可证、可复现构建、签名、CVE 响应和回滚证据。