Skip to content

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=true
  • true:服务器要求普通聊天消息使用 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. 安全码和设备变化

  1. 安全码绑定当前会话、双方用户和对端已提交的全部 MLS 设备指纹。
  2. 应用必须展示 Core 返回的 safetyCodeverificationURI, 不得在 UI 层自行重算。
  3. 点击“已核验”时必须带回用户刚刚看到的安全码。如果期间 新增设备或密钥变化,操作会以 e2ee_identity_changed 失败, 不会把新身份误认为已核验。
  4. 同一设备指纹的信任会持久化;指纹改变后会恢复为未核验。
  5. 安全码是手工身份核验,不等同于独立的全局 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”、“绝对安全”或“已通过顶级密码学认证”:

  1. 独立密码学审计与修复复验;
  2. 浏览器/小程序的审核通过 OpenMLS WASM 和安全密钥存储;
  3. 真实 RTC Provider 的 SFrame 接线和真机互操;
  4. 独立可审计的 Key Transparency 服务;
  5. 全销售平台多设备、换机、成员增删、重放、断电恢复和恶意服务端矩阵;
  6. SBOM、依赖许可证、可复现构建、签名、CVE 响应和回滚证据。

XHIM 客户端 SDK 与服务端文档