在现代计算系统中,随机数无处不在,从生成密码到玩简单的彩票游戏。然而,在密码学领域,随机数的安全性不仅仅是以低概率“中奖”的问题,而是决定系统能否抵御攻击的关键因素。
如果随机数生成器不安全,可能导致:
- 加密密钥的预测,使系统通信容易被破解;
- 会话令牌的伪造,导致用户账户的非法接管;
- 签名算法的失效,使数字签名失去合法性。
因此,在密码学应用中,我们需要的不仅仅是“看似随机”的数字序列,还需要不可预测且安全的随机数。这就是 密码学安全伪随机数生成器 (CSPRNG) 的用武之地。
什么是 CSPRNG?
CSPRNG 是一种专为密码学应用设计的伪随机数生成器 (PRNG),具有更高的安全标准。
CSPRNG 的核心特性包括:
- 预测抵抗性:攻击者无法根据已知部分预测随机序列的其他部分。
- 向后不可追溯性:即使内部状态被攻击者窃取,先前生成的随机数序列也无法恢复。
为了理解 CSPRNG 的重要性,让我们将其与其他随机数生成方法进行比较。
随机数生成器的比较
-
真随机数生成器 (TRNG)
TRNG 基于物理现象(例如硬件噪声、电磁干扰)生成完全随机的值,但速度慢且强烈依赖于硬件。
-
伪随机数生成器 (PRNG)
PRNG 基于算法和种子生成随机数,效率高但可预测,不适合密码学场景。
-
CSPRNG
CSPRNG 基于密码学原理设计,解决了 PRNG 的安全漏洞,确保生成的随机数序列不可预测。
例如,PRNG 就像一个自动生成诗句的程序;只要知道起始句(种子),攻击者就可以预测后续句子。相比之下,CSPRNG 就像一个锁定诗句源代码的程序,使外界几乎无法预测下一句。
CSPRNG 的原理和算法
常见的 CSPRNG 算法
-
HMAC 确定性随机位生成器 (HMAC-DRBG)
基于 HMAC (基于哈希的消息认证码) 算法的 CSPRNG,使用密钥和伪随机值更新内部状态。HMAC-DRBG 通过双状态管理(密钥
K
和伪随机值V
)提高了不可预测性和向后不可追溯性。 -
基于 SHA-256 的 PRNG
基于 SHA-256 哈希算法的随机数生成器,不需要额外的密钥,仅依赖于状态值。其更新机制简单,但抵抗攻击的能力不如 HMAC-DRBG。
-
计数器模式确定性随机位生成器 (CTR-DRBG)
基于分组密码模式(如 AES)的随机数生成器,使用计数器 (CTR) 模式生成随机数。适用于高性能和高安全需求场景,依赖于分组密码算法的安全性,适合硬件实现。
随机种子生成
- 通过调用操作系统的真随机数生成器 (TRNG) 获取高熵种子。
- 使用硬件安全模块 (HSM) 或系统熵源(如
/dev/urandom
)生成种子,以确保 CSPRNG 初始状态的随机性。
如何使用 CSPRNG?
从前面的原理中我们知道,为了确保 CSPRNG 的有效性,我们应该从一个真正的随机种子开始。如果初始种子不能保证真正的随机性,那么理论上仅依靠 CSPRNG 算法很难确保随机数的真正密码学安全。
事实上,现代操作系统已经考虑到了这个问题,并提供了系统级的真随机数接口,这些接口大多基于底层熵源(如硬件噪声、键盘和鼠标事件)生成高质量的随机数。
例如,Linux 和 macOS 中的 /dev/random
和 /dev/urandom
接口,以及 Windows 中的 CryptGenRandom
或 BCryptGenRandom
接口。
常见的编程语言也提供了系统级真随机数接口的封装:
- Node.js 的
crypto.randomBytes()
方法; - Java 的
SecureRandom
类; - Python 的
os.urandom()
接口和secrets
模块等。
你可能会问,既然可以生成系统级的真随机数,为什么我们还需要 CSPRNG 算法?
如前所述,操作系统的熵池容量有限,这意味着它生成真随机数的速度有限。在短时间内需要大量随机数的场景中,系统级随机数无法满足要求。CSPRNG 是对系统级真随机数的增强,提供更快的密码学安全随机数生成,以及更高的定制化和更多的随机位等。
使用 CSPRNG 时,应注意以下几点:
- 如果使用普通的伪随机数种子,可能导致攻击者预测随机序列,导致 CSPRNG 输出不安全。我们可以使用前面提到的系统级接口生成真随机数作为种子。
- 如果 CSPRNG 的内部状态泄露,也可能导致生成的随机数被预测。为避免这种情况,我们可以定期更新 CSPRNG 的状态或种子。
应用示例
密钥生成
在加密通信中,密钥的安全性直接决定了系统的安全性。如果密钥是可预测的,攻击者可以通过暴力破解或分析密钥生成模式获得密钥,从而解密通信内容。因此,密钥生成需要极高不可预测性的随机数,而 CSPRNG 的特性(预测抵抗性和向后不可追溯性)确保生成的密钥难以预测。
会话令牌
在 Web 应用中,会话令牌用于标识用户会话(如登录状态)。如果令牌被攻击者猜测或伪造,可能导致会话劫持 (Session Hijacking),从而冒充用户进行操作。
例如,在 CSRF 和 PKCE 中,使用随机的 state
或 code
来防止会话或流程攻击。
还有其他场景,例如在使用哈希算法处理要写入 DB 的密码时,如果仅使用简单的哈希算法,很难抵御彩虹表攻击。在这种情况下,使用哈希算法时,添加一个随机变量 Salt,使相同的密码生成不同的哈希值。