端到端加密 #

Matrix 加密房间使用 OlmMegolm 这两个相关的 ratchet 协议。效果是:对加密房间而言,即便是主机服务器运营方(我们——Meldry)也只能看到密文。解密发生在你的客户端里,用的是永远不会离开设备的密钥。

本页讲清各个组件是怎么配合的,这样当 Element 提示你验证设备或保存恢复密钥时,你才知道它在做什么。

Olm 与 Megolm #

  • Olm——Signal 的 Double Ratchet 的 Matrix 实现,用于一对 设备 之间的 1 对 1 会话。Matrix 用它传递设备间消息(分享密钥、发秘密、验证身份),房间消息本身不直接用 Olm。
  • Megolm——建立在 Olm 之上的群组 ratchet。当你第一次在加密房间里说话时,你的设备生成一个 Megolm 会话 并把起始密钥材料(通过 Olm)分发给房间里每一台设备。之后大家都可以用 ratchet 向前解密你的消息,不再需要每条消息都握手一次。

为什么要拆成两层?Double Ratchet 为每 一对设备 提供完美前向保密,但放到群组里不 scale——需要 O(n²) 个 ratchet。Megolm 以 房间 为粒度提供单向前向保密(过去消息在当前密钥泄漏时安全,反之不然),同时把成员变动的代价降到 O(n)。

Megolm 会话何时轮转 #

  • 成员变动。 新成员加入 → 新会话(他们读不到历史)。有人离开 → 新会话(他们读不到未来)。
  • 时间 / 消息数量。 达到配置的消息数或墙钟时长(默认 100 条消息或 1 周)就自动轮转。
  • 手动。 Element 的安全设置里可以强制轮转。

轮转看起来就是消息流里出现了一瞬间的停顿——你偶尔会看到短暂的"无法解密",然后很快自愈。

设备密钥 #

你每一个登录的设备都会在首次启动时生成自己的一组长期 身份密钥(Curve25519 + Ed25519 对)。这些密钥的公钥会上传到你的主机服务器,让别人可以加密消息给你,但 私钥 永远不离开设备。

当 Alice 在一个加密房间里开始说话时,她的客户端会:

  1. 从 Bob 的主机服务器取 Bob 的设备列表。
  2. 对 Bob 的每一台设备,用 Bob 的设备身份密钥打开一条 Olm 会话(Double Ratchet)。
  3. 通过每条 Olm 会话发送起始的 Megolm 密钥(每台设备一次)。
  4. 用 Megolm 密钥加密房间消息写出。
  5. Bob 的设备先用 Olm 解出 Megolm 密钥,再用 Megolm 解出消息。

这些对用户都是透明的——全部在客户端里自动发生。用户唯一看见的就是"验证设备"这一步。

设备验证与跨签名 #

因为密钥是按设备隔离的,当你第一次在一台新手机上登录时,你的笔记本会看到"未验证设备"的警告。验证就是你用来确认"嗯,那个新设备确实是我(或确实是我正在聊天的朋友)"的动作:

  • Emoji 验证——两台设备各自显示从 64 个里抽取的 7 个 emoji。面对面或通过可信通道对比。(底层是从一次"密钥承诺交换"派生出来的 Short Authentication String。)
  • 二维码扫描——手机显示二维码,桌面扫描。底层和 emoji 验证用的是同一个 Short Authentication String。
  • 恢复密钥——如果你没有第二台设备,可以用初次设置加密时保存的 恢复密钥 来验证新设备。恢复密钥解锁你的跨签名身份。

跨签名 #

跨签名(Cross-signing) 是让设备验证规模化的机制。它给每个账户引入三把长期密钥:

  • 主签名密钥(MSK)——信任的根。你在第一次设置加密时生成,只生成一次。它给另两把密钥签名。
  • 自签名密钥(SSK)——给你自己的设备签名。当你添加一台新设备并验证后,新设备会被 SSK 签名,而 MSK 又为 SSK 背书,所以任何信任你 MSK 的人会自动信任新设备。
  • 用户签名密钥(USK)——给你已经验证过的其他用户签名。当你验证 Bob 后,你的 USK 会给 Bob 的 MSK 签名;之后任何信任你的人都会顺带信任 Bob 的整个身份。

最终效果:你只需要 每人验证一次(而不是每个设备都验一次),这份验证在重装系统或换设备后依然生效。

安全秘密存储(SSSS) #

你的跨签名私钥、Megolm 密钥备份密钥和其他长期秘密会被一个口令加密后,以一段不透明 blob 的形式存到主机服务器上,叫 SSSS(Secure Secret Storage and Sharing)。你在新设备上输入口令(或粘贴恢复密钥)即可解锁,只有你能解锁——服务器本身读不了。

这就是一台新设备在没有另一台已登录设备在场的情况下,仍然可以引导进入一个已存在的加密账户的机制。如果没有 SSSS,你要么需要老设备在线来给新设备跨签名,要么只能开一份新的跨签名身份(然后重新验证所有人)。

SSSS 使用 PBKDF2-HMAC-SHA512 从你的口令派生密钥。一个强口令(或一串随机恢复密钥)是你在服务器上的秘密的唯一屏障。

密钥备份 #

每一个 Megolm 会话都会被 单独 备份到主机服务器(用一把存在 SSSS 里的密钥加密)。这让你在新设备上登录时依然能解密旧的历史消息:登录 → 用口令解锁 SSSS → 取备份 → 解密旧的 Megolm 会话 → 解密旧消息。

如果没有密钥备份,丢了唯一另一台设备再重新登录,就意味着你的加密历史全部丢失——这是刻意设计的安全保证。服务器从未持有密钥,我们无法重建它们。

对 Meldry 用户的实际意义: 第一次设置加密时,Element 会提示你保存一个 恢复密钥务必保存。 手机丢了 + 没有其他设备 + 没有恢复密钥 = 加密历史丢失。没有"重置密码"能帮你找回消息。

什么被加密,什么不被加密 #

加密(E2EE):

  • 加密房间里的消息正文、反应、编辑、文件上传
  • 私聊(Meldry 默认为 DM 启用 E2EE)
  • 加密房间里的房间名称 / 话题 / 头像变更(在启用加密之后)
  • 你设备之间的 to-device 消息

不加密:

  • 公开房间(按设计——新加入者必须能读到历史)
  • 房间成员事件(主机服务器能看到谁在房间里)
  • 输入中提示、在线状态、已读回执(不敏感到需要加密)
  • 服务端元数据:你在哪些房间里、上次什么时候连线、设备数量

如果一个房间原本是公开的,后来才开启加密,那么 启用之后 的消息是加密的,但之前的消息保持明文。开启加密是单向开关——一旦启用不能关掉。

常见故障 #

"无法解密" 报错。 通常是你没有那条消息对应的 Megolm 会话。常见原因:

  • 消息是在你加入房间之前发的(密钥从来就没有分享给你)
  • 你在新设备上登录了但还没恢复密钥备份
  • 会话轮转正在进行中

每次重启都提示"验证本设备"。 你没有设置跨签名。去 Element 的 设置 → 安全与隐私 → 跨签名 → 设置

服务端报"会话过期 / 未找到"。 非常罕见,通常是主机服务器侧 bug。重启客户端;如果仍在,提交支持工单。

下一步 #