隨機數與密碼學:從偽隨機到真隨機

📅 發布日期:2025-01-27 ⏱️ 閱讀時間12 分鐘 🏷️ 分類:密碼學 / 資訊安全

前言:隨機數是現代密碼學的基石。從 HTTPS 加密連線、密碼生成、數位簽章到區塊鏈,無處不依賴高品質的隨機數。但你知道嗎?並非所有「隨機數」都真正隨機,更不是所有隨機數都適合密碼學應用。本文將深入解析 PRNG(偽隨機)、TRNG(真隨機)、CSPRNG(密碼學安全隨機)的原理與差異,並透過真實攻擊案例,說明隨機數安全的重要性。

偽隨機數生成器 (PRNG) 原理圖,展示種子、算法和輸出序列的關係
偽隨機數生成器 (PRNG) 原理圖,展示種子、算法和輸出序列的關係

一、隨機性的重要性:為什麼我們需要隨機數?

在資訊安全領域,不可預測性是最高原則。如果攻擊者能預測系統的行為,所有加密機制都形同虛設。隨機數扮演以下關鍵角色:

⚠️ 真實案例:Debian OpenSSL 弱隨機數漏洞(2008)

2006-2008 年間,Debian Linux 的 OpenSSL 套件存在嚴重漏洞:隨機數生成器的熵源被意外移除,導致只能產生 32,767 種可能的金鑰(正常應有 2^128 種)。

影響:所有使用該版本 OpenSSL 生成的 SSH 金鑰、SSL 憑證、GPG 金鑰都可在數小時內暴力破解。全球數百萬伺服器受影響,需緊急更換所有金鑰。

教訓:隨機數品質直接決定系統安全性,絕不能妥協。

真隨機數生成器 (TRNG) 工作原理圖,展示物理熵源和量子隨機性
真隨機數生成器 (TRNG) 工作原理圖,展示物理熵源和量子隨機性

二、PRNG(偽隨機數生成器):演算法的魔法

PRNG(Pseudorandom Number Generator,偽隨機數生成器)是透過確定性演算法產生看似隨機的數列。給定相同的種子(Seed),PRNG 會產生完全相同的輸出。

1. 經典 PRNG 演算法

線性同餘法(Linear Congruential Generator, LCG)

最古老、最簡單的 PRNG,公式:

X(n+1) = (a × X(n) + c) mod m // 參數範例(C 語言 rand()): a = 1103515245 c = 12345 m = 2^31

優點:速度極快
缺點:週期短、品質差、容易預測(絕不可用於密碼學

梅森旋轉(Mersenne Twister, MT19937)

目前最廣泛使用的 PRNG,Python 的 random.random() 底層實作。

2. PRNG 的致命弱點:可預測性

所有 PRNG 的核心問題:給定種子,輸出完全確定。如果攻擊者:

  1. 知道演算法(通常是公開的)
  2. 知道或猜測種子(如時間戳、process ID)
  3. 觀察到部分輸出

...就能預測所有未來輸出,破解加密系統。

⚠️ 真實案例:線上撲克網站隨機數漏洞(2013)

某線上撲克網站使用 Math.random()(基於時間戳的 LCG)產生洗牌順序。駭客透過:

  1. 觀察多局遊戲的發牌順序
  2. 推算伺服器時間戳(種子)
  3. 預測後續所有牌局

結果:駭客贏得數百萬美元,網站倒閉。

密碼學中隨機數的關鍵應用場景與安全最佳實踐,包含加密金鑰、初始向量、鹽值等用途
密碼學中隨機數的關鍵應用場景與安全最佳實踐,包含加密金鑰、初始向量、鹽值等用途

三、TRNG(真隨機數生成器):物理世界的混沌

TRNG(True Random Number Generator,真隨機數生成器)物理現象中提取隨機性,輸出完全不可預測。

1. TRNG 的熵源(Entropy Sources)

熵源 原理 應用
放射性衰變 放射性同位素衰變的時間完全隨機(量子現象) HotBits 服務(使用銫-137)
電子熱噪音 電阻中電子的隨機熱運動 Intel RDRAND 指令
大氣噪音 雷電、無線電干擾產生的隨機訊號 Random.org 服務
鍵盤/滑鼠時序 使用者操作的時間間隔(微秒級) Linux /dev/random
硬碟 seek 時間 硬碟讀寫頭移動的微小時間差 嵌入式系統

2. TRNG 的優缺點

優點

  • 完全不可預測:即使知道所有歷史輸出,也無法預測下一個值
  • 無週期:不會重複(在合理時間內)
  • 最高安全性:適用於最敏感的密碼學應用

缺點

  • 速度慢:需等待物理事件發生(如 /dev/random 可能阻塞)
  • 成本高:需特殊硬體(如輻射偵測器)
  • 可用性問題:熵源可能耗盡(如嵌入式設備無使用者輸入)

四、CSPRNG(密碼學安全隨機數):最佳平衡點

CSPRNG(Cryptographically Secure Pseudorandom Number Generator)是結合 PRNG 速度與 TRNG 安全性的方案:

  1. 從 TRNG 收集高品質種子(如 256 位元熵)
  2. 使用密碼學演算法(如 ChaCha20、AES-CTR)擴展種子
  3. 即使攻擊者知道部分輸出,也無法預測其他值

1. CSPRNG 的核心要求

2. 常見 CSPRNG 實作

平台/語言 CSPRNG API 底層機制
JavaScript (Browser) crypto.getRandomValues() 作業系統 CSPRNG(/dev/urandom 或 CryptGenRandom)
Python secrets 模組 /dev/urandom (Linux) CryptGenRandom (Windows)
Java SecureRandom SHA1PRNG + /dev/urandom
Linux /dev/urandom ChaCha20 (Kernel 4.8+)
Windows BCryptGenRandom AES-CTR

五、隨機數品質測試:如何驗證隨機性?

隨機數生成器的品質可透過統計測試套件驗證:

1. NIST SP 800-22 測試套件

美國標準技術研究院(NIST)制定的 15 項統計測試:

2. Diehard Tests

經典隨機性測試套件(15 項測試),檢測:

3. TestU01(最全面)

當前最嚴格的測試套件,包含三個等級:

六、常見隨機數攻擊與防禦

1. 種子預測攻擊

⚠️ 攻擊場景

某網站使用 srand(time(NULL)) 作為種子(C 語言)。攻擊者:

  1. 觀察會話令牌生成時間(如 HTTP header 的 Date
  2. 在該時間前後 10 秒內暴力嘗試所有可能種子(只需 20 次)
  3. 預測其他使用者的會話令牌

防禦:使用 CSPRNG(如 /dev/urandom)自動播種,避免人為指定種子。

2. 狀態洩露攻擊

梅森旋轉演算法的已知弱點:

防禦

  1. 使用 CSPRNG 而非一般 PRNG
  2. 定期重新播種(如每 10 分鐘從 /dev/urandom 注入新熵)
  3. 限制單次輸出數量

3. 熵耗盡攻擊

針對 Linux /dev/random(會阻塞直到有足夠熵)的 DoS 攻擊:

防禦:使用 /dev/urandom(不會阻塞,現代 Linux 已足夠安全)或硬體 RNG(Intel RDRAND)。

七、實作最佳實踐

1. JavaScript/TypeScript

// ❌ 錯誤:絕不使用 Math.random() 做密碼學應用 const badToken = Math.random().toString(36).substring(2); // ✅ 正確:使用 Web Crypto API function generateSecureToken(length = 32) { const array = new Uint8Array(length); crypto.getRandomValues(array); return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''); } const token = generateSecureToken(); // 64 位元組十六進位字串 console.log(token); // e.g., "a3f5c8d9e2b1..." // 生成密碼學安全的隨機整數 function secureRandomInt(min, max) { const range = max - min + 1; const bytesNeeded = Math.ceil(Math.log2(range) / 8); const maxValue = Math.pow(256, bytesNeeded); const threshold = maxValue - (maxValue % range); let randomValue; do { const randomBytes = new Uint8Array(bytesNeeded); crypto.getRandomValues(randomBytes); randomValue = randomBytes.reduce((acc, byte, i) => acc + byte * Math.pow(256, i), 0); } while (randomValue >= threshold); // 避免模偏差 return min + (randomValue % range); }

2. Python

import random import secrets # ❌ 錯誤:random 模組不適合密碼學 bad_token = ''.join(random.choices('0123456789abcdef', k=32)) # ✅ 正確:使用 secrets 模組(Python 3.6+) secure_token = secrets.token_hex(32) # 64 位元組十六進位 secure_urlsafe = secrets.token_urlsafe(32) # Base64 URL-safe # 密碼學安全的隨機整數 secure_int = secrets.randbelow(100) # 0-99 # 從列表中安全選擇 items = ['A', 'B', 'C', 'D'] choice = secrets.choice(items) # 生成強密碼 import string alphabet = string.ascii_letters + string.digits + string.punctuation password = ''.join(secrets.choice(alphabet) for _ in range(16))

3. 一般原則

密碼學隨機數的黃金法則

  1. 永遠使用 CSPRNG:JavaScript 用 crypto.getRandomValues(),Python 用 secrets
  2. 避免自行播種:讓作業系統處理(現代 OS 的 CSPRNG 已自動從多個熵源收集)
  3. 足夠的熵:金鑰至少 128 位元(AES-128),256 位元更佳(AES-256)
  4. 定期更新:長期運行的服務應定期重新初始化 CSPRNG
  5. 避免模偏差:生成範圍隨機數時,使用拒絕採樣(rejection sampling)

八、應用場景分析

應用場景 建議方案 理由
遊戲(單機) PRNG(如梅森旋轉) 速度快,品質足夠,可重現(給定種子)
線上賭博/抽獎 CSPRNG + 可驗證隨機性 需公平性證明,防玩家/營運商作弊
科學模擬 高品質 PRNG 需可重現性(相同種子重現實驗)
密碼生成 CSPRNG 安全性最重要
加密金鑰 CSPRNG(最好硬體 RNG) 最高安全需求
會話令牌 CSPRNG 防預測攻擊
抽樣調查 PRNG(足夠品質) 統計特性重於安全性

結論:隨機數是安全的基石

隨機數看似簡單,實則是密碼學與資訊安全的基礎。本文的核心要點:

  1. PRNG:快速但可預測,僅適合遊戲、模擬等非安全場景
  2. TRNG:完全隨機但速度慢,適合高安全需求(如 CA 根金鑰)
  3. CSPRNG:平衡速度與安全,所有密碼學應用的標準選擇
  4. 永遠使用 CSPRNG:JavaScript 用 crypto.getRandomValues(),Python 用 secrets
  5. 測試隨機性:使用 NIST SP 800-22 或 TestU01 驗證自訂 RNG
  6. 警惕攻擊:種子預測、狀態洩露、熵耗盡都可能破壞安全

記住:密碼學的安全性取決於最弱的一環。即使使用 AES-256 這樣的強加密演算法,如果金鑰是用 Math.random() 生成的,整個系統形同裸奔。投資時間理解隨機數,是成為優秀資安工程師的必經之路。

🎲 試用我們的密碼學安全隨機數生成器

基於 Web Crypto API 的高品質隨機數生成器,適用於密碼生成、抽獎、密鑰生成等場景。100% 本地處理,保護您的隱私!

立即試用 →