ChaCha20 加密
带可选认证的现代流密码
客户端安全
ChaCha20-Poly1305(RFC 8439)是推荐的认证加密模式。纯 ChaCha20 不提供完整性保护——生产加密始终使用 Poly1305。对于 96 位 IETF nonce:强制严格的 nonce 唯一性(基于计数器或每会话随机)。XChaCha20-Poly1305(192 位 nonce)支持安全的随机 nonce 生成。
初始块计数器值(加密通常为 0,解密使用相同值)
关于 ChaCha20
ChaCha20 是 Daniel J. Bernstein 于 2008 年设计的 ARX 流密码,作为 Salsa20 的改进变体。它在相同的 4×4 个 32 位字矩阵(512 位状态)上运行,但重新设计了季度轮函数和不同的状态初始化布局。ChaCha20 的季度轮比 Salsa20 实现更好的每轮位扩散:任何单位变化在 2 轮内传播到所有 16 个状态字(Salsa20 需要 4 轮)。IETF 变体(RFC 8439)使用 96 位 nonce(3×32 位)和 32 位计数器(支持每 nonce 最多 2³² × 64 = 256 GB),而 Bernstein 的原始版本使用 64 位 nonce 和 64 位计数器。
ChaCha20-Poly1305(RFC 7539,2015 年;更新的 RFC 8439,2018 年)是 IETF 标准化的 AEAD 构造,将 ChaCha20(加密)与 Poly1305(认证)相结合。一次性 Poly1305 密钥从计数器=0 的 ChaCha20 输出的前 32 字节派生。该构造提供 128 位认证标签。Google 于 2014 年为 Android 和低功耗设备在 TLS 中部署了 ChaCha20-Poly1305(Langley 和 Borsini)。它在 TLS 1.3(RFC 8446)中作为 TLS_CHACHA20_POLY1305_SHA256 是强制的,适用于无 AES 硬件(移动设备、嵌入式)和作为独立于 AES-NI 的替代方案。
算法对比
| 算法 | 类型 | 密钥长度 | Nonce 长度 | 最佳用途 |
|---|---|---|---|---|
| ChaCha20 | 流密码 | 256 bits | 96 bits (12 bytes) | 协议实现研究和测试;在更高协议层提供认证的密码流;无 AEAD 开销的性能基准测试 |
| ChaCha20-Poly1305 | AEAD | 256 bits | 96 bits (12 bytes) | TLS 1.3、WireGuard、SSH、QUIC、Signal 协议认证消息加密;无 AES-NI 的移动和嵌入式设备;需要时序攻击抵抗 AEAD 的面向互联网服务 |
| XChaCha20 | 流密码 | 256 bits | 192 bits (24 bytes) | 通过计数器无法保证 nonce 唯一性的文件和数据库字段加密;libsodium secretstream 用于分块文件加密;使用独立生成 nonce 的备份加密 |
| XChaCha20-Poly1305 | AEAD | 256 bits | 192 bits (24 bytes) | 需要随机 nonce 生成和 128 位认证的静态数据加密;基于 libsodium 的应用程序存储加密;无法集中协调 nonce 管理时推荐的默认 AEAD |
ChaCha20 工作原理
ChaCha20 初始化 4×4 矩阵,与 Salsa20 使用相同的 4 个常量字(“expa nd 32-byte k”),但布局不同:第 0 行 = 常量,第 1-2 行 = 256 位密钥(8×32 位),第 3 行 = [计数器₀ | nonce₀ | nonce₁ | nonce₂](IETF:32 位计数器 + 96 位 nonce)。对 (a,b,c,d) 的季度轮执行四个加法-异或-旋转步骤,旋转量为 16、12、8、7 位:a+=b; d^=a; d⋘16; c+=d; b^=c; b⋘12; a+=b; d^=a; d⋘8; c+=d; b^=c; b⋘7。
ChaCha20 的双轮对矩阵的四列应用季度轮(列轮),然后对四条对角线应用(对角线轮)。与 Salsa20 的行-对角线结构相比,ChaCha20 的列-对角线模式加上新的旋转常量(16-12-8-7 对比 Salsa20 的 7-9-13-18)在 2 轮内实现对所有 16 个字的完全位扩散(Salsa20 需要 4 轮)。20 轮(10 个双轮)后,输出块 = 20 轮变换状态与原始状态的 XOR。
AEAD:认证加密
ChaCha20-Poly1305 AEAD(RFC 8439):派生一次性 Poly1305 密钥:以计数器=0 运行 ChaCha20,取输出的前 32 字节。然后从计数器=1 开始用 ChaCha20 加密明文。计算 Poly1305 MAC:[填充的 AAD] || [填充的密文] || [小端 uint64 len(AAD)] || [小端 uint64 len(密文)]。将 16 字节 Poly1305 标签附加到密文。
XChaCha20-Poly1305:通过 HChaCha20(ChaCha20 对应 HSalsa20 的函数)从 192 位 nonce 的前 128 位和原始 256 位密钥派生 256 位子密钥。子密钥和剩余 64 位 nonce 输入 ChaCha20-Poly1305。192 位 nonce 支持随机 nonce 生成而不受生日界限制:2³² 条消息下碰撞概率仍为 2^(-128)。libsodium 将此实现为 crypto_aead_xchacha20poly1305_ietf_encrypt。
主要特性
- 对比 Salsa20 更好的每轮扩散:ChaCha20 的季度轮旋转常量(16-12-8-7)在 2 轮内实现任意位翻转到所有 16 个状态字的完全扩散;Salsa20 需要 4 轮实现等效扩散。这意味着 ChaCha20/8(8 轮)提供与 Salsa20/16 等效的安全性。
- IETF 标准化(RFC 8439,2018 年):ChaCha20-Poly1305 是 IETF 标准化的 AEAD;TLS 1.3(RFC 8446)强制要求 TLS_CHACHA20_POLY1305_SHA256;在 WireGuard、SSH OpenSSH、QUIC、Signal 协议、Noise 协议框架和 Android TLS 堆栈中采用。
- 独立于 AES 的性能:在 AES-NI 硬件加速出现前设计;在 ARM Cortex-A53/A55、嵌入式微控制器、RISC-V 和 MIPS 架构上表现优秀;在没有 AES-NI 指令的硬件上比 AES-GCM 快 25-40%;IoT、移动和资源受限部署的首选。
- 96 位 IETF nonce(3×32 位):每会话启用唯一 nonce,32 位计数器(每个 nonce 最多 256 GB),XChaCha20 扩展到 192 位 nonce,适用于需要随机 nonce 生成且无生日风险的应用。
- 截至 2025 年 ChaCha20/20(完整 20 轮)无已知攻击。最佳已发布精简轮分析:Shi 等人(2012 年)对 ChaCha20/6 的概率中性位差分。完整安全分析确认 ChaCha20/20 安全级别对于单目标攻击至少为 256 位。
安全注意事项
- Nonce 复用破坏 ChaCha20-Poly1305 AEAD:用相同(密钥,nonce)加密两条消息会暴露两个明文的 XOR,并且 Poly1305 认证密钥(从计数器=0 输出派生)被揭露,完全破坏认证。强制每条消息的 nonce 唯一性。TLS 1.3 中:nonce 从序列号 XOR 派生,确保会话内的唯一性。
- IETF nonce(96 位)计数器限制:32 位计数器最多支持 2³² × 64 字节 = 256 GB 每(密钥,nonce)。对于单个 nonce 下超过 256 GB 的数据量,递增 nonce 或重新密钥。实际上,TLS 1.3 在接近此限制前通过 key_update 重新协商密钥。
- Poly1305 一次性密钥要求:Poly1305 密钥必须每个 nonce 仅用于一条消息。如果 ChaCha20-Poly1305 nonce 被复用,Poly1305 密钥被复用,破坏认证(Bernstein 2005 重复 Poly1305 密钥伪造攻击)。RFC 8439 第 2.8 节规定每 nonce 一密钥构造。
- 认证标签截断:RFC 8439 强制要求完整 128 位(16 字节)Poly1305 标签。截断认证标签(如为节省空间降至 64 位)将伪造抵抗从 2^(-128) 降至 2^(-64),且不符合 TLS 1.3 要求。始终使用 16 字节完整长度标签。
实际应用
- TLS 1.3(RFC 8446):TLS_CHACHA20_POLY1305_SHA256 是 TLS 1.3 中的强制密码套件;在 OpenSSL、BoringSSL、NSS、WolfSSL 和 mbedTLS 中实现;对无 AES-NI 的客户端(移动、嵌入式)首选,通过恒定时间 ARX 操作提供时序攻击抵抗。
- WireGuard VPN:ChaCha20-Poly1305 是 WireGuard 密码模块中唯一的对称密码(Donenfeld 2017,Linux 内核 5.6);与 Curve25519(密钥交换)、Poly1305(MAC)、BLAKE2(哈希)和 SipHash(哈希表)结合;为简洁性、可审计性和受限硬件性能而选择。
- Signal 协议/双棘轮算法:Signal 在 X3DH 密钥协议后的双棘轮消息加密中使用 ChaCha20-Poly1305 作为对称 AEAD;也被 WhatsApp、Facebook Messenger 的秘密对话、Matrix 协议和 Keybase 采用。
- OpenSSH chacha20-poly1305@openssh.com:OpenSSH 6.5(2014 年)成为第一个采用 ChaCha20-Poly1305 的主要 SSH 实现;该密码使用两个独立的 ChaCha20 实例(一个用于数据包长度,一个用于有效载荷)以消除可变长度填充的时序泄露。
- Google 移动 TLS 部署(2014 年):Adam Langley 和 Thai Duong 为连接 Google 服务的 Chrome 和 Android TLS 部署了 ChaCha20-Poly1305;性能测量显示在没有 AES-NI 的 Nexus 5 ARM Cortex-A15 上比 AES-128-GCM 快 3 倍,影响了后续 IETF 标准化。