密码学基础回顾:对称加密与非对称加密、哈希函数、数字签名、随机数生成
说实话,很多人在学 TLS 的时候,一上来就被各种握手流程搞懵了。我当年也是这样。后来我发现,真正卡住你的不是协议本身,而是背后的密码学基础。这一章,我们就把这些基础概念彻底捋清楚。
你想想看,TLS 本质上就是在做三件事:身份认证、数据加密、完整性校验。这三件事,分别对应着非对称加密、对称加密和哈希函数。嗯,就是这么简单。
核心认知:TLS 不是发明了新的密码学算法,而是把现有的密码学工具组合成了一个安全的通信协议。理解每个工具的特性,你就能看懂 TLS 为什么这样设计。
对称加密:又快又简单,但有个大问题
对称加密,说白了就是加密和解密用同一个密钥。就像你家里的大门,用一把钥匙锁上,也用同一把钥匙打开。
常见的对称加密算法有:
- AES(Advanced Encryption Standard)—— 目前最主流的对称加密算法,TLS 1.3 里还在大量使用
- ChaCha20 —— 谷歌力推的流加密算法,在移动设备上性能更好
- 3DES —— 老古董了,TLS 1.3 已经彻底移除
对称加密最大的优势是快。我在项目中做过压测,AES-256-GCM 在普通服务器上每秒能加密好几 GB 的数据。但它的致命问题是——密钥分发。你想想看,如果通信双方事先没有见过面,怎么安全地把这把钥匙交给对方?
我的经验:曾经有个项目,团队直接用硬编码的 AES 密钥做客户端和服务器通信。上线第一天就被安全团队叫停了。密钥一旦泄露,所有历史数据都能被解密。对称加密的密钥管理,永远是第一道坎。
非对称加密:解决密钥分发难题
非对称加密的思路很巧妙。每个通信方都有一对密钥:公钥和私钥。公钥可以公开给任何人,私钥只有自己知道。
它的核心特性是:
- 用公钥加密的数据,只能用对应的私钥解密
- 用私钥加密的数据,只能用对应的公钥解密(这就是数字签名的基础)
常见的非对称加密算法:
| 算法 | 密钥长度 | 安全强度 | TLS 中使用情况 |
|---|---|---|---|
| RSA | 2048 / 4096 位 | 高 | 传统握手,TLS 1.3 中已不是必须 |
| ECDHE | 256 / 384 位 | 高(同等安全下密钥更短) | TLS 1.3 默认密钥交换 |
| Ed25519 | 256 位 | 极高 | 新兴方案,性能极佳 |
非对称加密的缺点是慢。RSA 2048 位签名比 AES-256 慢好几个数量级。所以 TLS 不会用它来加密实际数据,而是用它来安全地协商出一个临时对称密钥。
避坑指南:我曾经见过一个项目,直接用 RSA 公钥加密每一笔交易数据。结果服务器 CPU 直接被打满,响应时间从 10ms 飙升到 3 秒。记住:非对称加密只适合加密小数据,比如密钥、哈希值。大数据加密,永远交给对称加密。
哈希函数:数据的指纹
哈希函数能把任意长度的数据,压缩成一个固定长度的摘要。而且这个操作是单向的——从摘要反推原始数据,理论上不可能。
好的哈希函数需要满足三个特性:
- 抗碰撞性:很难找到两个不同的输入,产生相同的输出
- 单向性:从输出无法反推输入
- 雪崩效应:输入改一个比特,输出完全不一样
TLS 中常用的哈希函数:
- SHA-256 —— TLS 1.3 的默认哈希函数,输出 256 位摘要
- SHA-384 —— 用于更高安全等级的场景
- SHA-1 —— 已经不安全了,TLS 1.3 已移除
- MD5 —— 彻底废弃,不要在任何新项目中使用
关键点:哈希函数不是加密。加密是可逆的,哈希是不可逆的。很多人把这两个概念搞混,面试时经常被问到。
数字签名:证明这东西是你发的
数字签名 = 哈希函数 + 非对称加密。流程是这样的:
- 发送方对消息做哈希,得到摘要
- 发送方用自己的私钥加密这个摘要,生成签名
- 接收方用发送方的公钥解密签名,得到摘要 A
- 接收方自己对消息做哈希,得到摘要 B
- 如果 A == B,说明消息确实是发送方发的,且没有被篡改
你想想看,这里解决了两个问题:
- 身份认证:只有持有私钥的人才能生成有效的签名
- 完整性:消息一旦被改,哈希值就对不上了
在 TLS 中,数字签名主要用于证书验证。CA 机构用它的私钥给你的证书签名,浏览器用 CA 的公钥验证这个签名。这就是整个 HTTPS 信任链的根基。
我的习惯:在调试 TLS 连接问题时,我经常先用 OpenSSL 手动验证证书签名。命令很简单:openssl verify -CAfile ca.pem server.crt。如果这一步都过不了,握手肯定失败。
随机数生成:安全的基础
这个知识点经常被忽略,但我觉得它特别重要。TLS 的整个安全性,都建立在高质量的随机数之上。
为什么?
- 密钥交换时需要随机数来生成临时密钥
- 对称加密的 IV(初始化向量)需要随机数
- TLS 握手过程中的随机数用于防止重放攻击
随机数生成器分两种:
| 类型 | 特点 | 示例 | 能否用于密码学 |
|---|---|---|---|
| 伪随机数生成器(PRNG) | 基于算法,可预测(如果知道种子) | C 语言的 rand() | ❌ 不能 |
| 密码学安全伪随机数生成器(CSPRNG) | 基于熵源,不可预测 | /dev/urandom, getrandom() | ✅ 可以 |
我曾经踩过的坑:有个嵌入式项目,设备没有硬件随机数生成器,团队就用 rand() 来生成 TLS 握手的随机数。结果呢?每次重启设备,生成的随机数序列都一样。攻击者只要抓一次包,就能预测后续所有会话的密钥。后来我们换成了从 ADC 噪声中提取熵源,才解决问题。
在 Linux 系统上,我建议你始终使用 getrandom() 系统调用,或者从 /dev/urandom 读取。不要用 /dev/random,它会在熵池不足时阻塞,导致程序卡住。
把这些串起来:TLS 是怎么用它们的?
现在你知道了每个工具的作用,我们来看看 TLS 是怎么把它们组合起来的:
- 握手阶段:客户端和服务器交换随机数,协商密码套件
- 身份认证:服务器发送证书(包含公钥),客户端验证 CA 的数字签名
- 密钥交换:使用 ECDHE 等非对称算法,安全地协商出临时对称密钥
- 数据加密:用协商好的对称密钥(如 AES-GCM)加密实际传输的数据
- 完整性校验:AEAD 模式同时提供加密和完整性校验,一步到位
你看,每个密码学工具都用在了最合适的地方。非对称加密负责安全的密钥交换,对称加密负责高效的数据加密,哈希函数保证数据完整性,随机数确保每次会话都是独一无二的。
总结一下:学 TLS 不需要你成为密码学专家,但你必须理解这些基础工具的特性和局限性。知道什么场景该用什么工具,什么场景绝对不能混用。后面的章节,我们会一步步把这些知识应用到实际的 TLS 协议分析中。