最近我发现我手机(骁龙820平台)访问我的网站时,加密协议由CHACHA20变成了AES-128-GCM. 我起先认为是服务器配置错误,但是我发现访问Google同样没有使用CHACHA20. 但我让朋友测试的时候(骁龙801平台)访问我的站和谷歌依然为CHACHA20_POLY1305加密协议。

820and801

我在 V2ex 提问后得到了这样的解答,我来汇总一下。

谷歌推广CHACHA20的时候是因为移动端(主要是ARM)的处理器没有 AES 指令,所以用纯软件来跑 AES 的性能是远不如 CHACHA20 的。但是ARM在ARMv8及以后的处理器中加入了 AES 指令,在这些设备上的 AES 加密性能反而比 CHACHA20 快很多。同时大多数服务器为 X86设备 自带AES-NI 指令集加速,如果全部强制使用 CHACHA20 也浪费了服务器的硬件加速。所以在带有 AES-NI 指令集 的设备上面,会优先使用 AES-GCM 加密方式。

但是我们知道浏览器与服务器协商加密方式是浏览器将自己的支持列表发送给服务器,而且服务器会优先选择自己列表中最靠前的加密方式。那又怎么做到支持 AES 加速的设备使用 AES-GCM 不支持的设备使用 CHACHA20 呢?

那就要提到了等价加密算法组,这个功能在 Nginx 中将 ssl_prefer_server_ciphers设为 on就可以打开,这个功能的目的在于将两总加密算法视为等价,比如[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]这两种加密方式为等价 。这样,因为 Chrome 会在不同的平台发送不同顺序的加密算法列表,如果不支持 AES 指令,那么 Chrome 发出的算法列表内 CHACHA20 会在第一位,服务器端 AES-GCM 与 CHACHA20 等价,服务端会优先使用 CHACHA20 。如果设备支持 AES 指令,那么 AES-GCM 应该在 Chrome 发出的支持列表首位,服务端采用 AES-GCM 作为加密方式。

因为我将这个站迁移到自己的 VPS 上面的时候比较懒,直接用了使用了一个现成的 Nginx 配置,所以没有注意到 ssl_prefer_server_ciphers 有这个参数,所以大家在自己配置的时候还是建议将这个参数开启。