4、密码学基础(下):密钥对生成(RSA/ECC)、密钥存储安全(HSM、TEE)、随机数的重要性
好,咱们接着聊。上一节我们把哈希、对称加密、非对称加密这些概念理了一遍。这一节,咱们要碰点真家伙了——密钥对到底是怎么变出来的?生成完了放哪儿才安全?以及,那个容易被忽略的“随机数”,为什么我总说它是整个PKI的命根子。
说实话,刚入行那会儿,我觉得密钥生成不就是调个OpenSSL命令嘛,几秒钟搞定。直到有一次,我在一个嵌入式设备项目里,发现生成的RSA密钥对居然有规律可循……嗯,从那以后,我对“生成”这两个字就再也不敢马虎了。
4.1 密钥对生成:RSA 与 ECC 的“内功心法”
密钥对生成,说白了就是找两个数学上“互逆”的钥匙。一把公开,一把私藏。但RSA和ECC找钥匙的方法完全不同。
4.1.1 RSA:大整数分解的“老黄牛”
RSA的生成逻辑,我习惯用一句话记:找两个大素数,乘起来,然后算个逆元。具体步骤是这样的:
- 选两个大素数 p 和 q。注意,是“大”素数,现在至少2048位,也就是十进制600多位。随机挑,但得通过素性检验。
- 计算 n = p × q。n就是公钥的一部分,长度就是密钥长度。
- 计算欧拉函数 φ(n) = (p-1)(q-1)。这个值必须保密。
- 选一个公钥指数 e。常用65537,为什么?因为它是一个费马素数,二进制是10000000000000001,只有两个1,算得快。
- 计算私钥 d,满足 e × d ≡ 1 (mod φ(n))。d就是私钥的核心。
我在项目中见过有人为了省事,直接用OpenSSL默认参数生成1024位RSA。我当时的反应是:“赶紧换,这玩意儿现在用FPGA暴力分解,几天就破了。” 现在行业底线是2048位,我建议直接上4096位,虽然慢一点,但安心。
RSA 密钥强度对照表(2025年视角)
| 密钥长度 | 安全等级 | 我的建议 |
|---|---|---|
| 1024位 | 已不安全 | 立即淘汰,不要再用 |
| 2048位 | 当前可用 | 可接受,但建议逐步迁移 |
| 4096位 | 长期安全 | 我个人的首选,性能损失可接受 |
4.1.2 ECC:椭圆曲线的“短小精悍”
ECC就不一样了。它不靠大数分解,而是靠椭圆曲线上的“点乘”运算。你想想看,在一条曲线上,给定一个点G,你算 k×G 很容易,但给你 G 和 k×G,让你反推 k,难如登天。这就是椭圆曲线离散对数问题。
ECC生成密钥对的步骤简单得多:
- 选一条曲线 和曲线上的基点G。比如NIST P-256、secp256r1、或者国密SM2的曲线。
- 随机生成一个私钥 k,就是一个大整数。
- 计算公钥 Q = k × G,就是点乘运算。
你看,ECC的私钥就是一个随机数,公钥就是一个点。比RSA那一堆 p、q、n、φ、d 清爽多了。而且,256位的ECC,安全强度相当于3072位的RSA。我做过一个IoT项目,设备内存只有几百KB,RSA 2048位的密钥对生成要卡好几秒,换成ECC P-256,瞬间完成。这就是差距。
我的选择建议: 新项目,尤其是资源受限的设备,优先选ECC。如果是兼容老系统,或者需要做RSA签名验签的互操作,那就用RSA 4096位。别混着用,保持统一。
4.2 密钥存储安全:HSM 与 TEE 的“保险柜”
密钥生成出来,放哪儿?你总不能明文写在配置文件里吧?我曾经在一个客户现场,发现他们把私钥直接硬编码在C代码里……我当时就问他:“你这跟把银行卡密码贴在ATM机上有什么区别?”
密钥存储,核心就三个字:防泄露。方案分三六九等,我按安全等级排个序:
4.2.1 HSM:硬件安全模块,银行级的“金库”
HSM是专用硬件,专门干一件事:在硬件内部生成、存储、使用私钥,私钥永远不离开芯片。你调用HSM的API说“给我签个名”,它把数据拿进去,签完把结果吐出来,私钥你连看都看不到。
我参与过一个金融CA项目,根CA的私钥就放在一个HSM里。那个HSM有多夸张?
- 有物理防篡改外壳,一拆就自毁。
- 有密钥备份机制,但备份也是加密后分片存储。
- 操作需要智能卡+密码双因子认证。
说白了,你想偷那个私钥,得先过保安、过指纹锁、过防爆门,最后还得知道HSM的管理员密码。成本极高。
4.2.2 TEE:可信执行环境,手机里的“安全隔间”
TEE是CPU内部的一个安全区域。你的手机、平板、智能电视里基本都有。它和主操作系统(REE)隔离,运行在独立的“安全世界”里。
我做过一个手机端数字身份项目,用户的签名私钥就存在TEE里。App想签名,得通过TEE的API发起请求,TEE在内部用私钥算完,把签名结果返回。就算手机被root了,攻击者也拿不到TEE里的私钥——因为TEE的内存和存储,REE根本访问不了。
注意: TEE虽然安全,但它的安全强度取决于具体实现。有些低端手机的TEE实现有漏洞,我曾经见过一个案例,攻击者通过侧信道攻击从TEE里提取出了密钥。所以,TEE适合做“次一级”的密钥存储,根密钥还是建议用HSM。
4.2.3 软件存储:最后的“底线”
如果实在没有HSM和TEE,只能用软件存,那也得有底线:
- 加密存储: 私钥用设备唯一密钥加密后存文件系统。
- 白盒密码: 把密钥和算法混淆在一起,增加逆向难度。
- Android KeyStore / iOS Keychain: 利用系统级安全存储,虽然不如TEE,但比明文强百倍。
但我得说一句:软件存储只是“延缓”攻击,不是“阻止”攻击。有条件的,还是上硬件。
4.3 随机数的重要性:PKI的“地基”
聊完密钥生成和存储,我得专门说说随机数。你想想看,RSA的p和q怎么来的?ECC的私钥k怎么来的?都是随机数。如果随机数不够随机,整个PKI就是纸糊的。
我讲一个真实案例。2012年,有研究者发现某些嵌入式设备生成的RSA公钥,居然有大量重复的n值。一查原因,是设备里的随机数生成器坏了,每次开机都返回相同的“随机数”。结果就是,所有设备的私钥都一样。你想想,这有多可怕?
4.3.1 真随机 vs 伪随机
| 类型 | 来源 | 特点 | 典型例子 |
|---|---|---|---|
| 真随机数(TRNG) | 物理噪声源 | 不可预测,但速度慢 | 芯片热噪声、放射性衰变 |
| 伪随机数(PRNG) | 算法+种子 | 可复现,速度快 | /dev/urandom、OpenSSL的RAND_bytes |
在PKI里,我们通常用PRNG,但种子必须来自TRNG。说白了,就是拿一小段真随机数,去“喂养”一个伪随机数生成器,让它源源不断地产出高质量的随机数。
4.3.2 随机数的“三大纪律”
我总结过三条,每次做安全评审都会拿出来对照:
- 不可预测性: 攻击者即使知道之前的随机数,也无法推断下一个。
- 均匀分布: 0和1出现的概率应该各占50%,不能有偏。
- 无周期性: 不能出现重复的模式。
我曾经在评审一个物联网平台时,发现他们用的随机数库是标准C库的rand()。我当时就指出:“这个库的周期只有2^31,而且种子是时间戳,攻击者只要知道设备上线时间,就能预测所有密钥。” 后来他们换成了基于硬件TRNG的随机数方案。
避坑指南: 永远不要用 rand()、srand(time(NULL)) 生成密钥。在Linux上,用 /dev/urandom 或 getrandom()。在嵌入式设备上,优先使用芯片自带的硬件随机数生成器(HRNG)。
4.4 本章知识体系:一张图看懂
下面这张图,我把密钥对生成、存储安全、随机数三者的关系画了出来。你一看就明白:随机数是源头,密钥生成是过程,安全存储是归宿。
你看,整个链条从随机数开始,到密钥生成,再到安全存储,任何一个环节出问题,整个PKI体系就垮了。我这些年做安全评审,发现90%的问题都出在随机数质量或密钥存储上。生成算法本身反而很少出错——因为大家都用标准库。
我的个人习惯: 每次项目启动,我都会先问三个问题:
- 随机数从哪里来?有没有硬件熵源?
- 密钥在哪儿生成?HSM、TEE还是软件?
- 私钥存哪儿?怎么防泄露?
这三个问题问完,项目的安全基线基本就定了。
好了,这一节的内容就到这儿。密钥对生成和存储,是设备PKI里最“硬核”的部分之一。理解了这些,后面讲证书签发、设备注册,你就知道为什么每一步都要这么“折腾”了。