3. 密码学基础(下):数字签名、密钥交换、随机数与PKI
好,咱们接着往下聊。上一节我们把对称加密、非对称加密和哈希函数过了一遍,这些都是TLS的“砖块”。这一节要讲的,是这些砖块怎么砌成墙——数字签名保证身份、密钥交换保证安全握手、随机数保证不可预测,而PKI则是整个信任体系的骨架。
我个人习惯把这一章叫做“TLS的信任链”。你想想看,没有这些机制,加密再强也没用——你连对面是谁都不知道,加密给谁呢?
3.1 数字签名:不只是“签个名”
数字签名,说白了就是用私钥加密一段摘要,别人用公钥验证。但这里有个关键点:签名不是加密整个消息,而是加密消息的哈希值。
核心流程:
- 发送方对消息做哈希,得到摘要
- 用私钥加密摘要,生成签名
- 接收方用公钥解密签名,得到摘要A
- 接收方对消息做哈希,得到摘要B
- 比较A和B,一致则签名有效
我在项目中遇到过一个问题:有人直接用RSA加密整个消息当签名。结果消息太长,RSA根本处理不了。嗯,这就是没理解“哈希+签名”这个组合的意义。
常见的签名算法有这些:
| 算法 | 密钥长度 | 签名长度 | 典型场景 |
|---|---|---|---|
| RSA-PSS | 2048-4096 bit | 与密钥等长 | TLS证书签名 |
| ECDSA | 256-521 bit | 64-132字节 | 嵌入式TLS握手 |
| Ed25519 | 256 bit | 64字节 | 轻量级设备 |
我的建议:在嵌入式场景下,优先选ECDSA或Ed25519。RSA签名太长,对MCU的RAM和Flash都不友好。我曾经在一个Cortex-M4的项目里用RSA 4096签名,结果每次握手要多花200ms——后来换成ECDSA P-256,直接降到30ms。
3.2 密钥交换:DH与ECDH
密钥交换解决的是这个问题:两个从没见过面的人,怎么在公开信道上商量出一个只有他俩知道的秘密?
DH(Diffie-Hellman)就是答案。它的数学原理其实不复杂:
- 双方约定一个大素数p和一个生成元g
- 各自生成随机私钥a和b
- 计算公钥A = g^a mod p,B = g^b mod p
- 交换公钥后,各自计算共享密钥:K = B^a mod p = A^b mod p
你看,中间人即使拿到了p、g、A、B,也计算不出a或b——这就是离散对数问题的难解性。
但DH有个问题:计算太慢了。尤其是p选得很大时,模幂运算在嵌入式设备上简直是噩梦。
所以有了ECDH——把DH搬到了椭圆曲线上。同样的安全强度,ECDH的密钥更短、计算更快。
| 安全等级 | DH密钥长度 | ECDH密钥长度 |
|---|---|---|
| 80 bit | 1024 bit | 160 bit |
| 128 bit | 3072 bit | 256 bit |
| 256 bit | 15360 bit | 512 bit |
注意:ECDH虽然快,但曲线选择很关键。我曾经见过有人用secp256r1(P-256)以外的曲线,结果库不支持,调试了整整两天。嵌入式开发里,曲线兼容性比理论安全性更现实。建议统一用NIST P-256或Curve25519。
3.3 随机数生成:TLS的“命根子”
这句话我说得很重,但事实如此。TLS里几乎所有安全机制都依赖随机数:
- DH/ECDH的私钥
- TLS握手的Client Random和Server Random
- 对称加密的IV(初始化向量)
- 会话ID和Cookie
随机数一旦可预测,整个TLS连接就形同虚设。我见过一个案例:某IoT设备用rand()生成TLS随机数,结果每次重启后握手随机数都一样——攻击者直接重放攻击,轻松破解会话。
嵌入式设备上怎么生成真随机数?
| 方案 | 原理 | 优缺点 |
|---|---|---|
| 硬件TRNG | 利用芯片内部热噪声 | 真随机,但部分MCU没有 |
| ADC噪声采样 | 悬空ADC引脚读噪声 | 成本低,速率慢 |
| 外部熵源 | WiFi/蓝牙射频噪声 | 依赖外设,不稳定 |
| 混合方案 | 硬件熵源+软件熵池 | 推荐做法,兼顾安全与性能 |
我的做法:在STM32上,我习惯用RNG外设(硬件TRNG)作为主熵源,同时用系统滴答定时器的低几位作为辅助熵源。每次TLS握手前,至少收集128字节的随机熵,再通过SHA-256做一次熵提取。这样即使硬件RNG有偏差,也能保证输出均匀。
3.4 证书与PKI:信任的锚点
数字签名解决了“消息是谁发的”,但没解决“这个公钥到底属于谁”。证书就是干这个的——它是一个数字身份证,把公钥和身份绑定在一起。
PKI(公钥基础设施)是管理证书的完整体系,包括:
- CA(证书颁发机构):签发证书的权威机构
- RA(注册机构):验证申请者身份
- 证书库:存储和分发证书
- CRL/OCSP:证书吊销机制
X.509证书是最常用的格式,里面包含:
证书结构(简化版):
├── 版本号 (V3)
├── 序列号
├── 签名算法 (如 sha256WithRSAEncryption)
├── 颁发者 (CA的DN)
├── 有效期 (notBefore / notAfter)
├── 主体 (证书持有者的DN)
├── 主体公钥信息 (算法 + 公钥)
├── 扩展字段 (密钥用途、基本约束等)
└── CA的签名
在嵌入式TLS里,证书验证是性能瓶颈。我做过一个测试:在ESP32上验证一个2048位RSA证书链(根CA+中间CA+设备证书),耗时约1.2秒。换成ECDSA P-256后,降到0.3秒。
避坑指南:我曾经在一个项目里直接硬编码了根证书,结果根证书过期后所有设备都连不上服务器。后来我加了证书过期检查和OTA更新机制。记住:证书有生命周期,嵌入式设备必须能更新信任锚。
3.5 知识体系总览
下面这张图把这一章的核心逻辑串起来了。你看,数字签名、密钥交换、随机数和PKI不是孤立的——它们共同构成了TLS握手的信任基础。
嗯,这一章的内容确实不少。但你要记住:密码学不是拼积木,而是搭骨架。每个组件都有它的位置和职责,少一个都不行。