什么是 CSPRNG?安全乱数产生器的历史、演算法与应用

1. 什么是 CSPRNG?

CSPRNG(Cryptographically Secure Pseudo-Random Number Generator),中文通常译为密码学安全伪随机数产生器,是在一般 PRNG(Pseudo-Random Number Generator)的基础上,额外满足密码学安全要求的乱数产生器。

一个 CSPRNG 至少需要具备两项核心特性:

  1. Next-bit Test(下一位不可预测性)

即使已知前 n 个输出位元,也无法在多项式时间(Polynomial Time)内,以高于 50% 的成功率预测第 n+1 个位元。

  1. State Compromise Resilience(状态泄漏韧性)

即使攻击者取得目前的内部状态,也无法回推出先前已产生的乱数。

简单来说,

CSPRNG 所产生的输出,在计算上无法与真正的随机数区分。


2. PRNG 与 CSPRNG 比较

| 特性 | PRNG(例如 Xorshift128+) | CSPRNG(例如 ChaCha20) | |------|-------------------------|--------------------------| | 速度 | 极快(约 2–3 ns/数值) | 很快(约 10–20 ns/数值) | | 是否可预测 | 可以,取得部分输出即可推回内部状态 | 几乎不可行 | | 周期 | 2¹²⁸ − 1 | 约 2²⁵⁶(ChaCha20) | | 可用于密码学 | ❌ 不可 | ✅ 可以 | | 常见 API | Math.random() | crypto.getRandomValues()/dev/urandom |


3. 发展历史

3.1 Blum Blum Shub(1986)

1986 年,

Lenore Blum、Manuel Blum 与 Michael Shub 提出了 Blum Blum Shub(BBS)

它是第一个具有严格数学安全证明的 CSPRNG。

其核心公式为:

# BBS
# x(n+1) = x^2 mod M
# M = p × q(两个大型质数乘积)

def bbs(seed, p, q, n):
    M = p * q
    x = seed
    bits = []

    for _ in range:
        x = (x * x) % M
        bits.append(x & 1)

    return bits

由于需要大量模平方运算,

BBS 非常缓慢,

因此主要具有理论研究价值,

却奠定了现代 CSPRNG 的基础。


3.2 Yarrow 与 Fortuna(1999/2003)

Bruce Schneier 与 Niels Ferguson 先后提出:

  • Yarrow(1999)
  • Fortuna(2003)

其中:

  • Yarrow 曾被 macOS、FreeBSD 的 /dev/random 采用。
  • Fortuna 引入多个 Entropy Pool,自动管理熵来源,避免单点失效。
  • 两者皆以 AES-256 作为核心区块加密演算法。

自 macOS 10.12(Sierra)起,

Apple 已改采 Fortuna。


3.3 ChaCha20(2008 至今)

Daniel J. Bernstein 于 2008 年设计 ChaCha20

它是 Salsa20 的改良版本,

也是目前最广泛采用的 CSPRNG 之一。

例如:

  • Linux 4.8(2016)起,/dev/urandom 采用 ChaCha20。
  • OpenBSD 自 2013 年起将 arc4random() 改为 ChaCha20。
  • Chrome、Node.js 的 crypto.getRandomValues() 建立于作业系统提供的安全乱数来源。
  • Rust 的 rand_chacha 预设使用 ChaCha 演算法。

4. 现代 CSPRNG 演算法

4.1 ChaCha20

ChaCha20 是一种 Stream Cipher

内部使用:

  • 4 × 4 Matrix
  • 共 16 个 32-bit Word
  • 总共 512 位元状态

核心 Quarter Round:

function quarterRound(state, a, b, c, d) {
  state[a] += state[b];
  state[d] ^= state[a];
  state[d] = rotl32(state[d], 16);

  state[c] += state[d];
  state[b] ^= state[c];
  state[b] = rotl32(state[b], 12);

  state[a] += state[b];
  state[d] ^= state[a];
  state[d] = rotl32(state[d], 8);

  state[c] += state[d];
  state[b] ^= state[c];
  state[b] = rotl32(state[b], 7);
}

ChaCha20 每个 Block:

  • Key:256 bit
  • Nonce:96 bit
  • Counter:32 bit
  • Output:512 bit

经过 20 轮(Rounds) 运算产生乱数。


4.2 AES-CTR-DRBG(NIST SP 800-90A)

AES-CTR-DRBG 是 NIST 标准,

广泛应用于:

  • 美国政府
  • 金融系统
  • FIPS 认证产品

简化结构如下:

class CTR_DRBG:
    def __init__(self, entropy, nonce):
        self.key = AES_key_from(entropy, nonce)
        self.counter = 0

    def generate(self, n):
        ...

特色:

  • 使用 AES-CTR 模式。
  • 定期 Reseed。
  • 符合 NIST SP 800-90A。

4.3 HMAC-DRBG(RFC 6979)

HMAC-DRBG 以 HMAC-SHA256 为核心。

RFC 6979 使用它来产生:

Deterministic ECDSA Nonce

可避免重复使用 Nonce 而泄漏私钥。

基本流程:

Seed
   │
   ▼
K
V
   │
   ▼
HMAC 更新
   │
   ▼
Random Output

5. 实际应用

CSPRNG 几乎存在于所有现代资讯安全系统中,包括:

  • TLS/HTTPS:Session Key、IV、Nonce。
  • SSH:金钥交换。
  • OAuth、JWT:Access Token、Refresh Token。
  • 密码系统:Salt、随机密码。
  • 区块链:Bitcoin、Ethereum 私钥。
  • 线上博弈:Provably Fair 随机种子。

6. 各程式语言 API

JavaScript(Browser / Node.js)

// Browser
const buf = new Uint8Array(32);
crypto.getRandomValues;

// Node.js
import { randomBytes, randomUUID } from "node:crypto";

const key = randomBytes(32);
const uuid = randomUUID();

Python

import secrets
import os

token = secrets.token_urlsafe(32)
pin = secrets.randbelow

raw = os.urandom(32)

# 不可用于安全用途
import random

⚠️ random 模组使用 Mersenne Twister,并非 CSPRNG。


Rust

use rand::rngs::OsRng;
use rand::RngCore;

let mut key = [0u8; 32];
OsRng.fill_bytes(&mut key);

Java

SecureRandom rng = SecureRandom.getInstanceStrong();

byte[] key = new byte[32];
rng.nextBytes;

int pin = rng.nextInt;

C(Linux)

#include <sys/random.h>

unsigned char key[32];
getrandom(key, sizeof(key), 0);

7. 著名安全事件

Debian OpenSSL(2008)

  • CVE-2008-0166
  • 误删两行程式码。
  • Entropy 仅剩约三万种可能。
  • Debian 约两年间产生的 SSL 金钥几乎都可被暴力破解。

Sony PS3(2010)

Sony 在 ECDSA 中重复使用固定 Nonce(k)。

结果:

  • 私钥被推算。
  • PS3 遭全面破解(Jailbreak)。

Android SecureRandom(2013)

Android 初始化乱数时熵不足,

导致大量 Bitcoin 钱包私钥遭窃。


DualECDRBG(2013)

DualECDRBG 是 NIST 标准中的一种 DRBG。

2013 年曝光其可能遭 NSA 植入后门,

成为密码学史上最具争议的事件之一,也使业界重新检视随机数产生器的设计与标准制定流程。