ChaCha20 是什么
ChaCha20 是 RFC 8439 定义的流密码:256 位密钥、协议层 96 位 nonce、32 位计数器,核心是 20 轮由加法、旋转与异或组成的运算(ARX)。它不依赖查表,所以软件实现的性能稳定,在没有 AES 硬件加速的移动与嵌入式设备上通常比 AES 更快。在 TLS 中它一般以 ChaCha20-Poly1305 这种带认证的组合形式出现。
基本信息
| 标准 | RFC 8439 |
|---|---|
| 密钥与 nonce | 256 位密钥,协议层 96 位 nonce |
| 计数器 | 32 位,决定单条密钥流的最大长度 |
| 轮数 | 20 轮,即 10 个双轮 |
| 典型组合 | ChaCha20-Poly1305(AEAD) |
| 适用场景 | 缺少 AES 硬件加速的移动与嵌入式设备 |
典型使用场景
- TLS 套件选择:为缺少 AES 加速的设备优先提供 ChaCha20-Poly1305
- 移动端与嵌入式加密:软件实现性能稳定,不依赖特定指令集
- 协议设计:把 ChaCha20 与 Poly1305 组合成带认证的加密方案
- 性能排查:同一服务在不同客户端表现差异大时,对比实际选用的套件
Python 使用示例
Python 使用示例
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
import os
# 裸流密码:注意该接口的 nonce 是 128 位(含内部计数器)
key, nonce = os.urandom(32), os.urandom(16)
enc = Cipher(algorithms.ChaCha20(key, nonce), mode=None).encryptor()
ct = enc.update(b'data') + enc.finalize()
# 实际使用建议走 AEAD 接口:nonce 为 96 位且自带完整性校验
aead = ChaCha20Poly1305(os.urandom(32))
sealed = aead.encrypt(os.urandom(12), b'data', None)与 AES-GCM 对照
| 维度 | ChaCha20-Poly1305 | AES-GCM |
|---|---|---|
| 硬件依赖 | 无,纯软件即可高效运行 | 有加速指令时优势明显 |
| 无加速时的性能 | 稳定且较好 | 通常较慢 |
| nonce 长度 | 96 位(协议层) | 96 位 |
| 主要风险 | nonce 重复 | nonce 重复与标签截断 |
| 生态支持 | TLS 1.3 标配 | TLS 各版本标配 |
裸 ChaCha20 不提供完整性保护;协议中应使用 ChaCha20-Poly1305(AEAD),并保证同一密钥下 nonce 不重复。
nonce 长度差异是最容易踩的坑:cryptography 库的 ChaCha20 原语接口接收 128 位 nonce(后 32 位作为内部计数器),而 AEAD 接口使用 96 位 nonce,两种写法不能互换。
计数器长度的含义:32 位计数器意味着单条密钥流最多覆盖约 256 GB 数据,超长数据流需要分段并更换密钥或 nonce,否则会触及回绕边界。
在 TLS 1.3 中它与 AES-GCM 并列,客户端通常同时声明两者,服务端按硬件能力与优先级选择;除非有明确理由,不必人为禁用其中一个。