gmsm

确定性随机数发生器(DRBG)与软件随机数发生器应用指南

目录


参考标准

国家标准 (GB/T)

国际标准

您可以从国家标准全文公开系统在线阅读国家标准。

概述

本软件库提供了两个层级的随机数生成能力:

  1. drbg/:底层 DRBG(确定性随机比特发生器)原语实现,支持三种机制:SM3 Hash DRBG、SM4 CTR DRBG 和 HMAC DRBG。适用于需要直接控制 DRBG 参数的场景。
  2. rand/:面向应用的软件随机数发生器,完全符合 GM/T 0105-2021 规范。内部使用 SM3 Hash DRBG 作为生成机制,结合三重熵源和 SP 800-90B 健康测试,提供与 crypto/rand 兼容的 API。

对于大多数应用场景,推荐直接使用 rand/

架构设计

┌─────────────────────────────────────────────────┐
│                  应用程序                         │
│     sm2.GenerateKey(rand.Reader)                │
└─────────────┬───────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────┐
│              rand/                               │
│  Reader (io.Reader)    Read(b []byte)           │
│  ┌─────────────────────────────────────────┐    │
│  │ SM3 Hash DRBG (GM 模式)                  │    │
│  │ atomic.Pointer + sync.Pool 并发管理       │    │
│  │ 自动重播种(按计数/时间间隔)               │    │
│  │ 每次 Read 混入 OS 附加输入                 │    │
│  │ 首次使用前执行 KAT 自检                    │    │
│  └─────────────────────────────────────────┘    │
└─────────────┬───────────────────────────────────┘
              │ Seed() 获取种子
              ▼
┌─────────────────────────────────────────────────┐
│           internal/entropy/                      │
│  ┌──────────┐ ┌──────────┐ ┌──────────────┐    │
│  │ OS 熵源   │ │ 抖动熵源  │ │ 哈希循环熵源  │    │
│  │crypto/rand│ │CPU jitter│ │runtime noise │    │
│  └─────┬────┘ └─────┬────┘ └──────┬───────┘    │
│        │  SP 800-90B │ 健康测试     │            │
│        ▼             ▼             ▼            │
│  ┌─────────────────────────────────────────┐    │
│  │        熵池(Twisted GFSR,附录 A.3)      │    │
│  │   128×32-bit 循环移位寄存器混合           │    │
│  │   SM3_df (Hash_df) 压缩提取              │    │
│  │   前向安全性反馈                          │    │
│  └─────────────────────────────────────────┘    │
└─────────────────────────────────────────────────┘

DRBG 基础包(drbg/)

drbg/ 包实现了三种 DRBG 机制,同时支持 NIST SP 800-90A 模式和 GM/T 0105-2021 国密模式。

支持的 DRBG 机制

机制 GM 模式 NIST 模式 说明
SM3 Hash DRBG 基于 SM3 杂凑算法,推荐用于国密场景
SM4 CTR DRBG 基于 SM4 分组密码算法
HMAC DRBG 基于 HMAC,仅支持 NIST 模式

GM 模式与 NIST 模式的差异

GM/T 0105-2021 对 DRBG 提出了更严格的要求:

使用示例

SM3 Hash DRBG(GM 模式)

import "github.com/emmansun/gmsm/drbg"

// 创建基于 SM3 Hash DRBG 的伪随机数发生器(GM/T 0105-2021 模式)
prng, err := drbg.NewGmHashDrbgPrng(nil, 32, drbg.SECURITY_LEVEL_TWO, nil)
if err != nil {
    panic(err)
}

buf := make([]byte, 32)
_, err = prng.Read(buf)
if err != nil {
    panic(err)
}

SM4 CTR DRBG(GM 模式)

import "github.com/emmansun/gmsm/drbg"

// 创建基于 SM4 CTR DRBG 的伪随机数发生器(GM/T 0105-2021 模式)
prng, err := drbg.NewGmCtrDrbgPrng(nil, 32, drbg.SECURITY_LEVEL_TWO, nil)
if err != nil {
    panic(err)
}

buf := make([]byte, 32)
_, err = prng.Read(buf)
if err != nil {
    panic(err)
}

底层 DRBG 直接使用

如果需要更精细的控制(如自定义熵源、手动重播种),可以直接使用底层 DRBG 接口:

import "github.com/emmansun/gmsm/drbg"

// 直接创建 SM3 Hash DRBG 实例
entropyInput := make([]byte, 32) // 从安全熵源获取
nonce := make([]byte, 16)        // 从安全熵源获取
// ... 填充 entropyInput 和 nonce ...

hd, err := drbg.NewGMHashDrbg(drbg.SECURITY_LEVEL_TWO, entropyInput, nonce, nil)
if err != nil {
    panic(err)
}
defer hd.Destroy() // 使用完毕后销毁内部状态

output := make([]byte, 32)
err = hd.Generate(output, nil) // 生成随机字节
if err == drbg.ErrReseedRequired {
    // 需要重播种
    newEntropy := make([]byte, 32)
    // ... 获取新的熵输入 ...
    hd.Reseed(newEntropy, nil)
}

软件随机数发生器(rand/)

rand/ 包是面向应用的高层接口,完全符合 GM/T 0105-2021 规范,提供与 Go 标准库 crypto/rand 一致的 API。

核心接口

import "github.com/emmansun/gmsm/rand"

// 全局 Reader,可直接传递给需要 io.Reader 的密码学 API
var Reader io.Reader

// Read 将随机字节填入 b,始终返回 len(b), nil
func Read(b []byte) (n int, err error)

// SetSecurityLevel 设置 DRBG 安全等级(影响后续创建的 DRBG 实例)
func SetSecurityLevel(level drbg.SecurityLevel)

使用示例

基本使用

import "github.com/emmansun/gmsm/rand"

// 生成 16 字节随机数
buf := make([]byte, 16)
n, err := rand.Read(buf)
if err != nil {
    panic(err)
}
// n == 16, buf 已填充随机字节

通过 io.Reader 接口使用

import (
    "io"
    "github.com/emmansun/gmsm/rand"
)

buf := make([]byte, 32)
n, err := io.ReadFull(rand.Reader, buf)
if err != nil {
    panic(err)
}

与 SM2 密钥生成集成

import (
    "github.com/emmansun/gmsm/rand"
    "github.com/emmansun/gmsm/sm2"
)

// 使用符合 GM/T 0105-2021 的随机数发生器生成 SM2 密钥对
key, err := sm2.GenerateKey(rand.Reader)
if err != nil {
    panic(err)
}

// 使用 SM2 签名
msg := []byte("待签名消息")
sig, err := key.SignWithSM2(rand.Reader, nil, msg)
if err != nil {
    panic(err)
}

// 验证签名
ok := sm2.VerifyASN1WithSM2(&key.PublicKey, nil, msg, sig)

设置安全等级

import (
    "github.com/emmansun/gmsm/drbg"
    "github.com/emmansun/gmsm/rand"
)

// 设置安全等级为一级(更长的重播种间隔)
rand.SetSecurityLevel(drbg.SECURITY_LEVEL_ONE)

// 后续创建的 DRBG 实例将使用新的安全等级
buf := make([]byte, 32)
rand.Read(buf)

GM/T 0105-2021 合规特性

rand/ 包实现了 GM/T 0105-2021 规范要求的以下安全机制:

1. DRNG 自检(第 5.6.6 条)

首次产生随机数输出之前,自动执行已知答案测试(KAT)。测试流程为:实例化 → 重播种 → 生成(丢弃)→ 生成(验证输出),若输出与预期不符则 panic,确保 DRBG 实现正确。

2. 三重独立熵源(第 5.2 条)

每次播种从三个独立熵源收集熵:

熵源 实现方式 健康测试 熵估计
OS 系统随机数 crypto/rand.Reader 无(OS 保证质量) 8 bits/byte = 256 位/32 字节
CPU 抖动 高精度计时 + 内存访问噪声 重复计数 + 自适应比例 + LAG 预测器 1 bit/sample = 1024 位/1024 样本
哈希循环 16 次连续 SM3 计算 + runtime.Gosched() 重复计数 + 自适应比例 + LAG 预测器 1 bit/sample = 1024 位/1024 样本

熵估计依据

3. SP 800-90B 健康测试(第 5.5 条,附录 D)

对非 OS 熵源执行三项连续健康测试:

关于 LAG 测试:RCT 和 APT 均无法捕获交替源(如 160→161→160→161→…)——该源无连续重复(RCT 通过),且每个值出现 256 次(≤ 410,APT 通过)。LAG 预测器检测到第三对开始每次预测均正确(509/511 ≥ 411),因此失败。参考 jitterentropy-library v3 的 LAG 测试设计。

这些测试既作为上电健康测试(首次收集 ≥1024 样本),也作为连续健康测试(后续每批样本)。

4. 熵池混合(第 5.3 条,附录 A.3)

使用扭曲 GFSR(广义反馈移位寄存器)进行熵混合:

5. SM3_df 调节函数(附录 B)

原始熵通过 SM3 Hash_df 函数进行调节压缩:

\[\text{seed} = \text{Hash\_df}(\text{pool\_data}, 440)\]

其中 Hash_df 迭代计算 SM3 哈希,直到产生所需长度的输出。

6. 自适应过采样率(OSR)

区别于旧版本的固定重试沟遐,当非 OS 熵源健康测试失败时,采用自适应过采样率机制(参考 jitterentropy-library):

OSR 级别 每次采集样本数 精展计数(保守) 尝试次数
1(默认) 1024 1024 位 3
2 2048 1024 位 3
3 3072 1024 位 3
4(最大) 4096 1024 位 3

7. 自动重播种(第 5.6.4 条)

DRBG 根据安全等级自动重播种,无需应用程序干预。

8. 附加输入混入

每次 Read() 调用从 crypto/rand.Reader 获取 16 字节作为附加输入传入 Generate(),提供纵深防御。即使 DRBG 状态被泄露,输出仍然与新鲜的 OS 随机性混合。

9. 敏感参数清零(第 7.2 条)

所有中间熵缓冲区、种子和 nonce 在使用后立即清零,符合第 7.2 条表 1 对关键安全参数的管理要求。

熵源(internal/entropy/)

internal/entropy/ 包是内部包,不对外暴露 API。以下信息供理解内部机制参考。

OS 熵源

通过 crypto/rand.Reader 获取操作系统提供的随机字节。这是最可靠的熵源基线,在所有平台上可用。每次 Seed() 调用收集 32 字节(256 位熵)。

CPU 抖动熵源

通过高精度计时器测量 CPU 指令执行时间的微小差异。使用 32MB 的共享内存缓冲区(BSS 段分配,不使用时不消耗物理内存),通过 LCG 索引的随机内存访问产生缓存未命中,从而引入不可预测的时序抖动。

每次 Seed() 调用收集 1024 个样本。

哈希循环噪声源

将 SM3 哈希计算时序与协程调度抖动结合:

初始状态从当前计时器初始化,确保并发运行的协程起始于不同状态。 第三方参考:jitterentropy-library(Stephan Müller)hash loop 噪声源,以 SM3 替代 SHA3/SHAKE-256。

纯 Go 实现,无平台依赖。每次 Seed() 调用收集 1024 个样本(自适应 OSR 下最多 4096 个)。

安全等级

GM/T 0105-2021 定义了两个安全等级,控制 DRBG 的重播种策略:

安全等级 计数间隔 时间间隔 适用场景
一级 (SECURITY_LEVEL_ONE) $2^{20}$ 次生成 600 秒 低安全要求场景
二级 (SECURITY_LEVEL_TWO,默认) $2^{10}$ 次生成 60 秒 通用安全场景
测试 (SECURITY_LEVEL_TEST) 8 次生成 6 秒 仅供测试

默认使用二级安全等级。安全等级越高(数值越小),重播种越频繁,安全性越强,但相应的性能开销也越大。

使用建议

推荐用法

  1. 一般场景:直接使用 rand.Read()rand.Reader,无需关心底层 DRBG 细节
  2. SM2 密钥生成/签名:将 rand.Reader 传入 sm2.GenerateKey() 和签名函数
  3. 需要 GM/T 0105-2021 合规:使用 rand/ 包,默认配置即满足要求

不推荐用法

  1. 不要drbg.DrbgPrng 用于并发场景——它不是并发安全的,请使用 rand.Reader
  2. 不要手动管理 DRBG 的重播种——rand/ 包已自动处理
  3. 不要SECURITY_LEVEL_TEST 模式下运行生产代码

drbg/rand/ 的选择

场景 推荐 原因
应用层随机数需求 rand/ 自动管理熵源、播种、重播种、并发安全
需要自定义熵源 drbg/ 可传入自定义 io.Reader 作为熵源
需要 HMAC DRBG drbg/ rand/ 仅使用 SM3 Hash DRBG
需要 CTR DRBG drbg/ rand/ 仅使用 SM3 Hash DRBG
测试或研究目的 drbg/ 可精确控制所有参数

性能

rand.Read() 的性能主要取决于:

Seed() 耗时构成(13th Gen Intel Core i7-13700,Windows,~4.2ms/次):

SM3 Hash DRBG GM 模式下每次 Generate 最大输出 32 字节,大量数据生成时会多次迭代。对于性能敏感且不要求 GM/T 0105-2021 合规的场景,可考虑直接使用 crypto/rand