3. 公钥密码学基础
说实话,很多搞PKI的人,到最后对底层的密码学还是一知半解。这其实挺危险的。你没法判断一个方案到底安不安全。
我个人习惯,在深入信任模型之前,先把“地基”打牢。这章我们就聊聊RSA、ECC和密钥对。这些东西是后面所有逻辑的起点。
3.1 密钥对:一个锁,一把钥匙,但身份不同
对称加密大家熟,就一把钥匙,开锁锁门都用它。公钥密码学不一样,它天然就生成“一对”钥匙。
- 私钥:自己藏好。这是你的数字身份。泄露了,等于你这个人可以被冒充。
- 公钥:可以公开。别人拿它来验证你是不是你,或者给你加密消息。
核心只有两个操作:
- 加密:用你的公钥加密,只有你的私钥能解开。
- 签名:用你的私钥签名,别人可以用你的公钥验证签名是不是你干的。
这个逻辑一旦搞反,整个PKI就全乱套了。
我曾经见过一个项目:他们把签名用的私钥直接拿去当加密密钥用,结果密钥泄露后,整个系统的历史通信都被解密了。记住,签名是法律效力,加密是隐私保护,用的密码学原语刚好相反。
3.2 RSA:老大哥,至今仍是主力
RSA是1977年发明的,到现在快50年了。之所以还在用,是因为它的数学原理足够牢靠。简单说,它基于一个事实:
两个大质数相乘很容易,但把一个大数分解成两个质数,难如登天。你想想看,一个2048位的数,你要去猜它是哪两个质数的乘积,这计算量,宇宙毁灭都算不完。
嗯,这里要注意,RSA的密钥对生成过程其实很“重”。
# RSA密钥对生成的核心流程(简化)
1. 随机选择两个大质数 p 和 q (需满足特定随机性要求)
2. 计算 n = p * q // n 就是公钥的一部分
3. 计算欧拉函数 φ(n) = (p-1)(q-1)
4. 选择一个整数 e (通常为 65537), 满足 1 < e < φ(n)
5. 计算 d, 使得 (d * e) % φ(n) == 1 // d 就是私钥
# 公钥: (n, e)
# 私钥: (n, d)
我刚开始做证书库的时候,觉得RSA生成密钥慢无所谓。后来在生产环境压测,发现并发量一大,CPU直接飙红。因为RSA私钥运算(比如签名)非常消耗性能,尤其是在移动设备上。
| 特性 | RSA 优势 | RSA 劣势 |
|---|---|---|
| 安全性强度 | 经过近50年密码分析考验,极其成熟 | 密钥长度不断增加(2048位起步,现在推荐4096位) |
| 性能 | 加密与签名验证速度尚可 | 签名与解密速度非常慢(相较于ECC) |
| 密钥体积 | 公钥相对较大(2048位),但网络传输不是瓶颈 | 私钥体积也大,对存储和传输有一定开销 |
| 适用场景 | CA根证书、代码签名、数字信封(加密对称密钥) | 频繁签名的场景(如TLS握手)、资源受限设备 |
一个小经验:在PKI系统中,根CA和二级CA的私钥,我们通常用RSA-4096。因为这些CA证书有效期长,需要最强的抗量子计算储备(虽然现在还没有量子计算机能攻破4096位RSA,但我们要未雨绸缪)。而终端实体证书(比如SSL证书),为了兼顾兼容性与性能,通常用RSA-2048或ECC。
3.3 ECC:后来居上,轻量战士
ECC,椭圆曲线密码学。它的核心优势就一句话:相同安全强度下,密钥尺寸更小,计算速度更快。
为什么会这样?RSA的数学基础是“因数分解”,而ECC的数学基础是“椭圆曲线离散对数问题”。说白了,攻破ECC需要的计算量是指数级的,比RSA要难得多。所以ECC用256位就能达到RSA-3072位或更高的安全等级。
我遇到过很多客户,一听到用ECC就担心兼容性。其实现在主流的浏览器、操作系统,对ECC的支持已经非常好了。
| 安全等级(位) | RSA 密钥长度(位) | ECC 密钥长度(位) |
|---|---|---|
| 80 | 1024 | 160 |
| 112 | 2048 | 224 |
| 128 | 3072 | 256 |
| 192 | 7680 | 384 |
| 256 | 15360 | 521 |
上面的表格很直观。想达到相同的安全等级,ECC的密钥长度只有RSA的十分之一左右。这意味着什么?
- 带宽压力小:TLS握手时,证书传输更快。
- 计算负荷低:服务器每秒可以处理更多TLS握手。
- 存储空间省:对IoT设备,这点很关键。
踩坑提醒:ECC虽然好,但你不能随便用一条曲线。NIST P-256(secp256r1)是业界最通用的标准。千万别用一些奇奇怪怪的曲线,尤其是那些声称“自己研发”的私有曲线。我以前有个同事,为了省事儿用了OpenSSL不默认支持的曲线,结果在客户的老系统上完全无法互通,现场排查了整整两天。
3.4 密钥管理与边界设计
技术懂了,但落到工程实践上,核心其实是“边界”。哪部分是硬件?哪部分是软件?哪部分归CA管?哪部分归用户管?
答案是:私钥永远不能离开它被生成的边界。
我个人习惯,把密钥对的生存周期分成三个阶段:
- 生成:必须在安全环境中生成。可以是HSM(硬件安全模块)、TPM(可信平台模块),或者签名服务器。
- 存储:私钥必须加密存储,而且密码必须高强度、唯一。不要硬编码到代码里。
- 使用:私钥只用于签名或解密,不要挪作他用。用完立即从内存中清除。
你看看下图,就知道RSA和ECC在实际PKI中的边界到底划在哪里:
你看,根CA的私钥,牢牢锁在HSM里,谁也别想把它提取出来私钥。二级CA在签名服务器里,私钥也是加密存储的。到了终端用户(比如你的浏览器),ECC私钥就存在你的操作系统安全存储或硬件TPM里。
3.5 实战中的避坑指南
最后,我给你总结几个我踩过的坑,或者见过别人踩的坑:
- 不要在代码中硬编码私钥密码:曾经有个安全审计项目,我发现他们把HSM的PIN码直接写在Java类里,而且代码还提交到了Github公共仓库。后果?整个CA被重新颁发所有证书。
- 不要混用密钥用途:签名密钥和加密密钥必须分开。签名密钥不能用来加密,加密密钥不能用来签名。这是PKI最基本的原则。我见过用SSL证书的私钥去签代码的,出了问题责任说不清。
- 选择正确的曲线:如果你用ECC,请默认使用NIST P-256。别为了“创新”选P-521(虽然理论上更安全,但性能差,兼容性差)。更不要用SM2(国家商用密码算法)去对接国外系统,反之亦然。
- 重视密钥生命周期:生成、使用、轮换、销毁,每一步都要有记录,有审计。我以前在一家金融公司,他们规定CA私钥每3年必须轮换一次,而且旧私钥必须物理销毁(用粉碎机粉碎HSM芯片)。听起来很夸张,但这是对用户负责。
一句话总结:公钥是门牌号,私钥是家里的钥匙。RSA是厚重牢固的防盗门,ECC是灵巧坚固的指纹锁。选哪个,取决于你的门框(场景)能承受多重的门,以及你希望开锁有多快。