2. SM2 密钥对生成原理:私钥、公钥、随机数质量
咱们直接聊密钥对是怎么来的。SM2 的密钥对生成,说白了就是两步:先捏一个私钥,再用私钥算出公钥。但这两步里藏着一个最要命的隐患——随机数质量。我做了这么多年的安全审计,至少有一半的密钥泄露事故,根子都在随机数上。
2.1 私钥:从随机数到私钥
SM2 的私钥,就是一个在 [1, n-2] 区间内随机选取的大整数。这里的 n 是 SM2 椭圆曲线的阶,一个固定的 256 位素数。具体怎么选?
- 从可靠的随机源拿到 256 位随机字节序列;
- 将其转换成整数 k;
- 检查 k 是否在 [1, n-2] 内——不在就重新生成;
- 得到的 k 就是私钥。
听起来简单吧?但我在项目里见过有人偷懒,直接用系统 rand() 拼出来的“随机数”当私钥。嗯,那种随机数的周期只有 2^31,暴力破解用不了一秒。
千万记住:私钥的随机性直接决定密钥的安全性。随机数一旦可预测,私钥就形同虚设。我曾经审计过一个嵌入式项目,他们用了硬件随机数发生器,但芯片复位后种子没有重新初始化,导致每次上电都生成相同的私钥——这不是密钥,是定时炸弹。
2.2 公钥:椭圆曲线上的点乘
有了私钥 k,公钥就是椭圆曲线上一个点的标量倍乘:P = [k]G。G 是 SM2 标准曲线上的基点,固定不变的。k 个 G 相加,结果 P 就是公钥。
这个运算很难反向:从 P 求 k 就是椭圆曲线离散对数问题,目前没多项式解法。所以只要私钥保密、随机数安全,公钥怎么公开都没事。
我在一次性能调优中遇到过:点乘实现用了倍点加算法,但没做侧信道防护。攻击者通过功耗分析,能反推出私钥的每一位。这提醒我们:不仅随机数要强,实现也不能有物理泄露。
# SM2 密钥对生成核心流程(伪代码)
def generate_sm2_keypair():
while True:
k_bytes = secure_random(32) # 32 字节 = 256 位
k = bytes_to_bigint(k_bytes) # 转大整数
if 1 <= k <= n - 2: # n 为曲线阶
break
P = point_mul(k, G) # 点乘,G 为基点
return (k, P) # (私钥, 公钥)
2.3 随机数质量——最脆弱的环节
为什么随机数质量这么关键?因为私钥就是随机数。如果随机数熵不够,或者生成器被预测,攻击者可以把整个密钥空间缩小到很小的范围。
| 随机数质量等级 | 熵源 | 检测标准 | 典型应用 | 风险等级 |
|---|---|---|---|---|
| 安全级 | 物理噪声源(量子/热噪声) | GM/T 0005-2012 全部检测 | CA 在线生成密钥 | 低 |
| 增强级 | 混合熵源(硬件 + 系统熵池) | 部分随机性检测 | 服务器端密钥生成 | 中 |
| 基础级 | 软件伪随机(如 /dev/urandom) | 基本统计检验 | 普通终端应用 | 中高 |
| 不安全级 | 纯定时器、固定种子 | 未检测或无检测 | 玩具项目、测试代码 | 极高 |
你想想看,一个固定种子的伪随机数生成器,换台机器、换个时间跑,结果一模一样。这种“密钥”跟出厂默认密码没区别。
我的个人习惯:在审计项目时,我会先检查随机数生成器的种子更新策略。如果发现种子只在系统启动时获取一次,之后就一直复用,我会立刻标记为高危。因为一旦某次随机数被泄露,所有历史密钥都能被反推出。
2.4 典型随机数坑——我踩过的和见过的
- 陷阱一:随机数范围没剪裁。生成 256 位随机数后直接当私钥用,没检查是否小于 n。虽然概率极低,但一旦越界,点乘会得到无效结果,或者私钥不自洽。
- 陷阱二:多线程并发生成时共用状态。没有加锁或者没有使用线程安全的随机数发生器,结果两个线程拿到了相同的随机数——私钥一模一样。我在云服务的日志里见过这种情况,一天内生成了两对重复密钥。
- 陷阱三:用弱 PRNG 代替真随机。某些老旧平台只提供了
rand()或random(),周期短、可预测。我见过一个 IoT 设备用srand(time(0))初始化——同一秒内的所有设备私钥全相同。
2.5 密钥对生成流程总览
下面这张图把整个过程串起来。注意看:随机熵源是一切的基础,它的质量决定了整个密钥的生死。
2.6 巡检要点清单
我每次做密钥生成巡检,都会对照这个清单逐项过。你也试试?
- 随机熵源是否符合 GM/T 0005-2012? 有没有通过国密局检测?
- 随机数生成器是否线程安全? 高并发场景下有无加锁或使用独立实例?
- 私钥范围检查是否实现? 代码里有没有
if k < 1 or k > n-2: regenerate()? - 点乘实现是否做了侧信道防护? 比如蒙哥马利阶梯、恒定时间算法。
- 生成后的密钥对是否立刻保护? 内存是否立即清零临时变量?
一句话总结:SM2 密钥安全的第一道防线不是算法强度,而是随机数质量。我以前在审计一个金融终端时,发现它的随机数发生器只用了系统 ticks,攻击者只要知道时间戳就能还原所有私钥。那个项目最后被勒令升级硬件熵源。别让随机数成为你系统的致命缺口。