这篇文章上次修改于 299 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
Signal 协议采用首次信任(Trust On First Use, TOFU)方法,用户盲目信任第一次连接时看到的密钥,并在未来拒绝任何更改。不过允许用户稍后对公钥验证,这种验证是在带外完成的,一般是比较公钥的十六进制表示或哈希值。
X3DH:Signal 协议的握手过程
X3DH 是密钥交换协议,可协商出加密会话的对称密钥。
前向保密需要密钥交换过程是交互式的,双方都必须生成临时的 DH 密钥对。X3DH 可以使得密钥交换是非交互式的,且仍能保证前向安全。
X3DH 本质上是将 3 个(或更多个)DH 密钥交换协议组成一个协议。
3 种 DH 密钥:
- long-term identity key pair --- 表示用户身份的长期密钥。
- several ephemeral prekey pairs --- 一些一次性预设密钥,使用后需删除。即使对方不在线的情况下,也能确保密钥交换的前向保密性。
- medium-term signed prekey --- 已签名的预设密钥,应该每隔一段时间(例如,一周)更换一次。用户上传的一次性预设密钥可能会用完,这时可以使用已签名的预设密钥来实现前向保密性。
Signal 协议握手过程如下:
Bob 向 Server 注册椭圆曲线公钥
- identity key $IK_B$
- signed preky $SPK_B$
- prekey signature $Sig(IK_B, Encode(SPK_B))$
- 可选:one-time prekey $(OPK_B^1, OPK_B^2, ...)$
- Alice 向 Bob 发起会话,需要向 Server 获取 Bob 的 prekey bundle
Alice 验证 $Sig(IK_B, Encode(SPK_B))$ 后,生成临时密钥对,其中公钥为 $EK_A$,然后执行 X3DH 密钥交换协议。
如果 prekey bundle 不包含 one-time prekey,则计算:
$$ \begin{align} &DH1 = DH(IK_A, SPK_B) \\ &DH2 = DH(EK_A, IK_B) \\ &DH3 = DH(EK_A, SPK_B) \\ &SK = KDF(DH1 || DH2 || DH3) \\ \end{align} $$
如果包含 one-time prekey,则计算
$$ \begin{align} &DH4 = DH(EK_A, OPK_B) \\ &SK = KDF(DH1 || DH2 || DH3 || DH4) \end{align} $$
其中,DH1 和 DH2 用于手动认证,DH3 和 DH4 提供前向保密性。
算出 $SK$ 后,Aice 会删除临时密钥和 DH 输出。
Alice 还会计算一个 "associated data" 二进制流 $AD$,会包含两方的身份信息:
$$ AD = Encode(IK_A) || Encode(IK_B) $$
也可以包含额外的信息,比如 Alice 和 Bob 都用户名、手机号等。
Alice 向 Bob 发送初始消息,包含 Alice 的:
- identity key $IK_A$
- ephemeral key $EK_A$
- 使用了 Bob 的哪个 one-time prekey
- 使用 $AD$ 和 $SK$ 加密的初始消息
Bob 收到 Alice 的初始消息后,从初始消息中获取 Alice 的 $IK_A$ 和 $EK_A$,加载自己的身份密钥、signed prekey 对应的私钥以及 one-time prekey 对应的私钥(如果 Alice 用了的话),同样使用 X3DH 算出共享密钥 $SK$。
Bob 使用 $IK_A$ 和 $IK_B$ 等信息构建出 $AD$,并用 $SK$ 和 $AD$ 解密初始消息。
解密成功后,为了前向保密性,删除使用过的 one-time prekey private key
Double Ratchet:Signal 握手结束之后的协议
接下来 Alice 和 Bob 把 X3DH 协议的输出当做会话密钥,用该会话密钥加密输出信息即可。
不过密码学中,希望不同用途的密码学算法使用不同的密钥,可以让 X3DH 协议的输出当作 KDF 算法的种子(或双棘轮协议的根密钥),进而派生另外两个新的密钥。Alice 用其中一个密钥加密发送给 Bob 的消息,而 Bob 用另外一个密钥加密发送给 Alice 的消息。Alice 发送消息的密钥和 Bob 接收消息的密钥相同,Bob 发送消息的密钥与 Alice 接收消息的密钥相同。
就安全性而言,这种方法足够了,但是不同于 TLS 会话,Signal 会话有效期可能长达数年,所以一旦会话密钥被窃取,之前的消息记录都可能被解密。如果每条发送或接收的消息都用一个唯一的 message key 加密就可以避免该问题,为此,Signal 引入了对称棘轮机制。发送密钥重命名为发送链密钥 chain key,但不直接用于加密消息。发送消息时,Alice 将该发送链密钥作为 KDF 的输入,KDF 会生成下一个发送链密钥和用于本次加密的实际密钥 message key。Bob 也执行类似的过程,不过操作的是接收链密钥。因此,即使泄露某个发送密钥或发送链密钥,攻击这也无法恢复之前的发送密钥(接收密钥同理),从而使得 Signal 协议具有前向保密性。过程如下:
Signal 协议也实现了后向保密,指即使密钥在某个时候泄露,攻击者也不能据此算出未来的 message key 以解密未来的消息。原理是引入新的熵,以替换上图中的 constant,而且攻击者无法获得这种熵。当然,协议的对等方必须获得一样的新熵。为此,Signal 引入了 DH 棘轮机制。每方都生产 DH 密钥对,作为当前的棘轮密钥对。发送送到每条消息公布公布公钥,该棘轮公钥可以与前一个棘轮公钥相同,如果参与者决定刷新其棘轮公钥,则公布新的棘轮公钥。如果 Bob 发现 Alice 提供了新的棘轮公钥,则利用 Alice 的新棘轮公钥和自己的棘轮密钥执行 DH 密钥交换操作。然后密钥交换协议的输出替换上图中的 constant。
DH 棘轮和对称棘轮称为双棘轮机制:
- 当发送或收到一条消息时,一个对称棘轮会被应用于发送链或接收链,以推出 message key
- 当收到一个新的棘轮公钥时,一个 DH 棘轮会被执行,以生成新的 chain key
参考
戴维-王. 深入浅出密码学[M]
没有评论