密码学基础:对称加密、非对称加密、哈希函数
要理解 TLS 1.3,得先搞定三个基本工具——对称加密、非对称加密、哈希函数。说白了,整个握手协议就是靠它们组装起来的。我带项目时见过不少开发者,上来就啃协议细节,结果被密钥协商绕晕。嗯,咱们先把地基打牢。
对称加密:快,但密钥怎么分?
对称加密大家应该不陌生。发送方和接收方用同一个密钥加密和解密。优势就一个字——快。硬件加速加持下,AES 跑个几十 Gbps 很轻松。但问题也明显:密钥怎么安全地交给对方?
现实中常用的对称算法是 AES(Advanced Encryption Standard)。TLS 1.3 里主要用 AES-GCM 和 ChaCha20-Poly1305,都是认证加密模式,既保密又防篡改。我踩过坑:当年一个项目里用 AES-CBC 加 HMAC,结果处理不当留了 padding oracle 漏洞,后来全改成了 GCM 模式,省心多了。
os.urandom(32) 生成 AES-256 密钥,每次不一样。
非对称加密:慢,但能解决密钥分发
非对称加密用一对密钥——公钥公开,私钥保密。数据用公钥加密后,只有私钥能解开。这就解决了密钥分发难题。你不用提前在双方之间共享密钥了。
TLS 1.3 握手阶段用非对称加密完成两件事:身份认证和密钥协商。证书里的公钥用于验证服务端身份,然后通过 ECDHE(椭圆曲线 Diffie-Hellman 密钥交换)协商出临时的对称密钥。我调试过一个问题:客户端的证书公钥是 RSA 2048,但协商时选了 ECDSA 签名,结果验签一直失败——算法不匹配,记住 证书和签名算法要配对。
哈希函数:不可逆的“指纹”
哈希函数把任意长数据变成固定长度的摘要。特点是单向——从摘要无法还原原文;抗碰撞——很难找到两个不同输入产生相同输出。TLS 1.3 里无处不在:握手消息的完整性校验、密钥派生、证书摘要都用到了哈希。
主流算法是 SHA-256 和 SHA-384。MD5 和 SHA-1 早就不安全了,别再用。我以前接手一个旧系统,文件完整性校验还是 MD5,同事觉得没问题。结果我模拟了一下碰撞攻击,两分钟就找到冲突文件,吓得他立刻改了 SHA-256。
# Python 哈希函数使用示例
import hashlib
data = b"TLS 1.3 handshake message"
sha256_hash = hashlib.sha256(data).hexdigest()
print(sha256_hash)
# 输出:f4a7...(固定长度 64 字符)
三者对比:各司其职
| 特性 | 对称加密 | 非对称加密 | 哈希函数 |
|---|---|---|---|
| 密钥数量 | 1 个密钥 | 公钥 + 私钥 | 没有密钥 |
| 速度 | 极快(硬件加速) | 慢(几百倍于对称) | 很快 |
| 主要用途 | 批量数据加密 | 密钥交换、数字签名 | 完整性校验、密钥派生 |
| 典型算法 | AES-256-GCM, ChaCha20 | RSA-3072, ECDH P-256 | SHA-256, SHA-384 |
| TLS 1.3 角色 | 保护应用数据 | 握手期间认证与协商 | 握手完整性、PRF 计算 |
一张图理清关系
我把三种密码学工具在 TLS 1.3 中的协作关系画了出来。
实战避坑指南
- 密钥长度别选错:对称加密至少 AES-128(推荐 AES-256);非对称 RSA 至少 3072 位,椭圆曲线至少 P-256;哈希至少 SHA-256。
- 随机数生成器要安全:不要用
random模块,用secrets或os.urandom。我曾经见过有人用 C 的rand()生成 IV,结果每次重启 IV 都相同,重放攻击直接破防。 - 不要自己实现密码算法:永远用经过审计的库,比如 Python 的
cryptography、OpenSSL、BoringSSL。自己造的轮子大多是窟窿。