某个 VPN 配置文件提供 448 位密钥的 Blowfish,有人提议用最长的密钥来保留这种加密。密钥长度是真的,但它是错误的优化目标。无论密钥多长,Blowfish 都按 64 位分组进行变换,而分组宽度才决定一把密钥能安全保护多少流量。请按顺序执行下面的检查,并在第一个能排除该服务的检查处停下,因为后面的步骤无法弥补前面的步骤。

检查双方实际协商的结果

从两端读取数据通道的加密算法,而不是看你打算部署的配置文件。客户端配置可能列出多种算法,最终选中的是两套实现及其版本协商的结果。在测试连接上提高日志详细程度,读取数据通道那一行,它会写明实际初始化的算法和密钥长度。

如果协商结果是 AES-GCM 或 ChaCha20-Poly1305,就到此为止。这些构造使用 128 位分组并对负载做认证,因此下面的 64 位碰撞论证对它们并不适用。

把密钥长度与分组宽度分开看

Blowfish 接受 32 到 448 位的密钥,算法作者的文档把这两个数字分开列出。密钥是秘密,分组是变换单位。把秘密加长只会让猜测更难,对加密所处理的分组宽度毫无影响。

在 CBC 模式下,加密作用于固定宽度的分组,与前一个密文分组链接,并在末尾填充。对 Blowfish 来说,这个宽度是 64 位,也就是八个字节。密钥编排可以任意大;链仍然每次只前进八个字节。

所以加长密钥并不是缓解措施。它针对的是对密钥的暴力破解,而下面的碰撞风险是分组宽度和模式的性质。

把生日界算术用到分组大小上

64 位分组的生日界大约是 2^32 个分组在同一密钥下加密之后,碰撞才会变得可能。每个分组携带八个字节,因此同一量级约为 2^35 字节,也就是单把密钥下的 32 GiB 数据。

把它当作量级,而不是配额。碰撞是概率性的,是否泄露信息取决于模式、流量形态,以及攻击者能否识别或影响周围的明文。超过 32 GiB 的第一个字节不是解密事件,前 32 GiB 也没有被认证为安全。

Sweet32 的研究者在 2016 年演示了对 64 位分组密码的实际攻击,其中包括 OpenVPN 场景,条件是需要观察并生成流量。他们公布的默认值和软件版本属于历史背景,并不是对你部署情况的描述。

判断 CBC 重用在这里是否重要

在 CBC 中,重复出现的密文分组意味着两个明文分组之间存在已知关系,因为链接 XOR 会相互抵消。能观察密文、并且知道或能影响其中一个明文的攻击者,可能据此恢复另一个明文的信息。为此从不需要 Blowfish 密钥。

因此关键问题是:一把密钥在役多久、它承载多少流量,以及是否有人能观察并引导这些流量。更换密钥会降低每把密钥的分组数,但时间间隔不是字节上限:同一小时内,繁忙隧道的传输量可能远超空闲隧道。如果你保留旧算法,请从构造和实际用量推导上限,而不是拍一个整数。

如果每把密钥的实测用量远低于生日界,暴露面就更小。但它仍然不是零,仍然值得规划迁移,而不是就此不再担心。

换掉算法,而不是换密钥

把服务迁移到受支持的 AEAD 算法,并确认双方、它们的版本以及各自的密码学后端都能协商它。加长 Blowfish 密钥不会改变任何重要的事情,而在单个客户端上猜测新指令,正是把可用隧道弄坏的方式。先在一个客户端和一台服务器上测试改动,再动其余设备。在新算法通过完整连接周期之前,保留旧配置以便回滚。

改动期间保留证书校验和账户认证。它们回答的是不同问题:成功登录不能拓宽分组,更好的数据加密也不能成为信任错误服务器的理由。

结束检查时,在新连接上再次读取协商出的算法,然后确认旧算法不再被接受。如果对端仍在提供它,无论对面配置怎么写,迁移都没有完成。

相关文章