{"slug":"csprng-la-gi-lich-su-thuat-toan-ung-dung-sinh-so-ngau-nhien-mat-ma","title":"CSPRNG Là Gì — Lịch Sử, Thuật Toán & Ứng Dụng Sinh Số Ngẫu Nhiên An Toàn","summary":"CSPRNG là gì? Lịch sử từ BBS (1986) đến ChaCha20 (2016), so sánh PRNG vs CSPRNG, thuật toán ChaCha20/AES-CTR-DRBG/HMAC-DRBG, API trong JS/Python/Rust/Java/C, và các lỗi bảo mật nổi tiếng.","excerpt":"CSPRNG là gì? Lịch sử từ BBS (1986) đến ChaCha20 (2016), so sánh PRNG vs CSPRNG, thuật toán ChaCha20/AES-CTR-DRBG/HMAC-DRBG, API trong JS/Python/Rust/Java/C, và các lỗi bảo mật nổi tiếng.","markdown":"# CSPRNG — Cryptographically Secure PRNG\n## 1. Định Nghĩa\nCSPRNG (Cryptographically Secure Pseudo-Random Number Generator — Bộ sinh số ngẫu nhiên giả an toàn về mặt mật mã) là PRNG thỏa mãn thêm 2 tính chất bảo mật:\n\nNext-bit test: Biết n bit đầu tiên, KHÔNG THỂ dự đoán bit thứ (n+1) với xác suất > 50% trong thời gian đa thức (polynomial time)\nState compromise resilience: Ngay cả khi attacker biết được state hiện tại, KHÔNG THỂ khôi phục các output trước đó\nNói đơn giản: CSPRNG tạo ra output mà ngay cả siêu máy tính cũng không thể phân biệt với số ngẫu nhiên thật.\n\n## 2. So Sánh PRNG vs CSPRNG\n| Tính chất | PRNG (Xorshift128+) | CSPRNG (ChaCha20) |\n\n| --- | --- | --- |\n\n| Tốc độ | Cực nhanh (2-3 ns/number) | Nhanh (10-20 ns/number) |\n\n| Dự đoán được? | Có — biết vài output → khôi phục state | Không — bất khả thi về mặt tính toán |\n\n| Chu kỳ | 2¹²⁸ − 1 | 2²⁵⁶ (ChaCha20) |\n\n| Dùng cho mật mã? | ❌ KHÔNG | ✅ CÓ |\n\n| API | Math.random() | crypto.getRandomValues(), /dev/urandom |\n\n## 3. Lịch Sử Phát Triển\n### 3.1. Thế hệ đầu: Blum-Blum-Shub (1986)\nLenore Blum, Manuel Blum và Michael Shub đề xuất BBS — CSPRNG đầu tiên có chứng minh bảo mật toán học. Dựa trên bài toán residuosity quadratic:\n\n// BBS: x(n+1) = x(n)² mod M\n// M = p × q (tích 2 số nguyên tố lớn)\n// Output: bit cuối cùng của mỗi x(n)\n\ndef bbs(seed, p, q, n):\nM = p * q\nx = seed\nbits = []\nfor _ in range(n):\nx = (x * x) % M\nbits.append(x & 1)  # lấy LSB\nreturn bits\n\n# Rất chậm — chỉ có giá trị lý thuyết\nBBS cực chậm (phải tính modular exponentiation) — chỉ có giá trị lý thuyết. Nhưng đặt nền tảng cho CSPRNG hiện đại.\n\n### 3.2. Yarrow & Fortuna (1999/2003)\nBruce Schneier (cùng Niels Ferguson) thiết kế Yarrow (1999) rồi Fortuna (2003):\n\nYarrow: Dùng bởi macOS/FreeBSD cho /dev/random (ban đầu)\nFortuna: Cải tiến — tự động quản lý nhiều entropy pool, tránh single point of failure\nCả hai dùng AES-256 làm block cipher nội bộ\nmacOS chuyển từ Yarrow sang Fortuna từ macOS 10.12 (Sierra).\n\n### 3.3. ChaCha20-based CSPRNG (2008–nay)\nDaniel J. Bernstein thiết kế ChaCha20 (biến thể của Salsa20). Hiện tại:\n\nLinux 4.8+ (2016): /dev/urandom dùng ChaCha20 thay LFSR\nOpenBSD arc4random(): ChaCha20 từ 2013\nChrome/Node.js crypto.getRandomValues(): ChaCha20 trên nền OS\nRust rand crate: ChaCha12 mặc định\n## 4. Các Thuật Toán CSPRNG Hiện Đại\n### 4.1. ChaCha20 — Stream Cipher CSPRNG\nChaCha20 là stream cipher hoạt động trên ma trận 4×4 (16 words, mỗi word 32-bit = 512 bits):\n\n// ChaCha20 quarter-round (core operation)\nfunction quarterRound(state, a, b, c, d) {\nstate[a] += state[b]; state[d] ^= state[a]; state[d] = rotl32(state[d], 16);\nstate[c] += state[d]; state[b] ^= state[c]; state[b] = rotl32(state[b], 12);\nstate[a] += state[b]; state[d] ^= state[a]; state[d] = rotl32(state[d], 8);\nstate[c] += state[d]; state[b] ^= state[c]; state[b] = rotl32(state[b], 7);\n}\n\nfunction rotl32(v, n) {\nreturn ((v << n) | (v >>> (32 - n))) >>> 0;\n}\n\n// 20 rounds = 10 × (4 column rounds + 4 diagonal rounds)\n// Input: 256-bit key + 96-bit nonce + 32-bit counter\n// Output: 512 bits ngẫu nhiên mỗi block\n### 4.2. AES-CTR-DRBG (NIST SP 800-90A)\nChuẩn NIST cho CSPRNG trong chính phủ Mỹ và ngành tài chính:\n\n# Cấu trúc AES-CTR-DRBG (simplified)\nclass CTR_DRBG:\ndef __init__(self, entropy, nonce):\nself.key = AES_key_from(entropy, nonce)  # 256-bit\nself.counter = 0\nself.reseed_counter = 0\n\ndef generate(self, num_bytes):\nif self.reseed_counter > 2**48:\nself.reseed()  # bắt buộc reseed\nblocks = []\nfor _ in range(num_bytes // 16 + 1):\nself.counter += 1\nblocks.append(AES_encrypt(self.key, self.counter))\nself.reseed_counter += 1\nreturn b''.join(blocks)[:num_bytes]\n### 4.3. HMAC-DRBG (RFC 6979)\nDùng HMAC-SHA256 làm core. Đặc biệt quan trọng cho deterministic ECDSA (tránh lỗi reuse nonce):\n\n// HMAC-DRBG pseudocode (RFC 6979)\n// K = HMAC key, V = value (both 256-bit)\nK = 0x00...00  (32 bytes)\nV = 0x01...01  (32 bytes)\n\n// Update:\nK = HMAC(K, V || 0x00 || seed_material)\nV = HMAC(K, V)\nK = HMAC(K, V || 0x01 || seed_material)\nV = HMAC(K, V)\n\n// Generate:\nV = HMAC(K, V)  → output\n// Mỗi lần generate xong phải update K, V\n## 5. Ứng Dụng Cụ Thể\nCSPRNG được dùng trong mọi hệ thống bảo mật:\n\nTLS/SSL: Tạo session key, nonce, IV cho mỗi kết nối HTTPS\nSSH: Tạo ephemeral key cho key exchange\nOAuth/JWT: Tạo access token, refresh token\nMật khẩu: Tạo salt cho bcrypt/argon2, tạo mật khẩu ngẫu nhiên\nBlockchain: Tạo private key (256-bit) cho ví Bitcoin/Ethereum\nGambling: Provably fair — seed được hash trước, reveal sau để chứng minh không gian lận\n## 6. API Trong Các Ngôn Ngữ\n### JavaScript (Browser & Node.js)\n// Browser\nconst buffer = new Uint8Array(32);\ncrypto.getRandomValues(buffer);\n\n// Node.js\nimport { randomBytes, randomUUID } from \"node:crypto\";\nconst key = randomBytes(32); // 256-bit key\nconst uuid = randomUUID();   // v4 UUID (122 random bits)\n### Python\nimport secrets\nimport os\n\n# Tạo token URL-safe\ntoken = secrets.token_urlsafe(32)  # 256-bit\n\n# Tạo số ngẫu nhiên trong range\npin = secrets.randbelow(1_000_000)  # 6-digit PIN\n\n# Bytes thô từ OS\nraw = os.urandom(32)\n\n# ⚠️ KHÔNG dùng `random` module cho bảo mật!\nimport random  # ❌ dùng Mersenne Twister — KHÔNG CSPRNG\n### Rust\nuse rand::rngs::OsRng;\nuse rand::RngCore;\n\nfn main() {\nlet mut key = [0u8; 32];\nOsRng.fill_bytes(&mut key); // /dev/urandom\nprintln!(\"256-bit key: {:?}\", key);\n\n// Hoặc dùng getrandom crate (lower-level)\nlet mut buf = [0u8; 16];\ngetrandom::getrandom(&mut buf).expect(\"failed\");\n}\n### Java\nimport java.security.SecureRandom;\n\nSecureRandom csprng = SecureRandom.getInstanceStrong();\nbyte[] key = new byte[32];\ncsprng.nextBytes(key); // 256-bit random key\n\n// Hoặc sinh số trong range\nint pin = csprng.nextInt(1_000_000); // 6-digit PIN\n### C (Linux)\n#include <sys/random.h>\n#include <stdio.h>\n\nint main() {\nunsigned char key[32];\n// getrandom() — Linux 3.17+ (glibc 2.25+)\nssize_t ret = getrandom(key, sizeof(key), 0);\nif (ret != sizeof(key)) {\nperror(\"getrandom failed\");\nreturn 1;\n}\n// key now contains 256 bits of CSPRNG output\nreturn 0;\n}\n## 7. Lỗi Bảo Mật Nổi Tiếng\nDebian OpenSSL (2008 — CVE-2008-0166): Comment nhầm 2 dòng code → entropy chỉ còn PID (~32,000 giá trị) → TẤT CẢ key SSL trên Debian trong 2 năm đều có thể brute-force\nSony PS3 ECDSA (2010): Dùng static k (nonce) cho ECDSA → lộ private key, jailbreak toàn bộ PS3\nAndroid SecureRandom (2013): Thiếu entropy initialization → ví Bitcoin trên Android bị trộm\nDual_EC_DRBG (2013): NSA cài backdoor trong chuẩn NIST — Kleptographic attack","html":"<h1>CSPRNG — Cryptographically Secure PRNG</h1><h2>1. Định Nghĩa</h2><p>CSPRNG (Cryptographically Secure Pseudo-Random Number Generator — Bộ sinh số ngẫu nhiên giả an toàn về mặt mật mã) là PRNG thỏa mãn thêm 2 tính chất bảo mật:</p><ol><li>Next-bit test: Biết n bit đầu tiên, KHÔNG THỂ dự đoán bit thứ (n+1) với xác suất &gt; 50% trong thời gian đa thức (polynomial time)</li><li>State compromise resilience: Ngay cả khi attacker biết được state hiện tại, KHÔNG THỂ khôi phục các output trước đó</li><p>Nói đơn giản: CSPRNG tạo ra output mà ngay cả siêu máy tính cũng không thể phân biệt với số ngẫu nhiên thật.</p></ol><h2>2. So Sánh PRNG vs CSPRNG</h2><p>| Tính chất | PRNG (Xorshift128+) | CSPRNG <span class=\"math-inline\" data-formula=\"ChaCha20\"><span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.6944em;\"></span><span class=\"mord mathnormal\" style=\"margin-right:0.07153em;\">C</span><span class=\"mord mathnormal\">ha</span><span class=\"mord mathnormal\" style=\"margin-right:0.07153em;\">C</span><span class=\"mord mathnormal\">ha</span><span class=\"mord\">20</span></span></span></span></span> |</p><p>| --- | --- | --- |</p><p>| Tốc độ | Cực nhanh (2-3 ns/number) | Nhanh (10-20 ns/number) |</p><p>| Dự đoán được? | Có — biết vài output → khôi phục state | Không — bất khả thi về mặt tính toán |</p><p>| Chu kỳ | 2¹²⁸ − 1 | 2²⁵⁶ <span class=\"math-inline\" data-formula=\"ChaCha20\"><span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.6944em;\"></span><span class=\"mord mathnormal\" style=\"margin-right:0.07153em;\">C</span><span class=\"mord mathnormal\">ha</span><span class=\"mord mathnormal\" style=\"margin-right:0.07153em;\">C</span><span class=\"mord mathnormal\">ha</span><span class=\"mord\">20</span></span></span></span></span> |</p><p>| Dùng cho mật mã? | ❌ KHÔNG | ✅ CÓ |</p><p>| API | Math.random() | crypto.getRandomValues(), /dev/urandom |</p><h2>3. Lịch Sử Phát Triển</h2><h3>3.1. Thế hệ đầu: Blum-Blum-Shub (1986)</h3><p>Lenore Blum, Manuel Blum và Michael Shub đề xuất BBS — CSPRNG đầu tiên có chứng minh bảo mật toán học. Dựa trên bài toán residuosity quadratic:</p><pre><code class=\"language-python\">// BBS: x(n+1) = xn² mod M</code></pre><pre><code class=\"language-python\">// M = p × q (tích 2 số nguyên tố lớn)</code></pre><pre><code class=\"language-python\">// Output: bit cuối cùng của mỗi xn</code></pre><pre><code class=\"language-python\">def bbs(seed, p, q, n):</code></pre><pre><code class=\"language-python\">    M = p * q</code></pre><pre><code class=\"language-python\">    x = seed</code></pre><pre><code class=\"language-python\">    bits = []</code></pre><pre><code class=\"language-python\">    for _ in rangen:</code></pre><pre><code class=\"language-python\">        x = (x * x) % M</code></pre><pre><code class=\"language-python\">        bits.append(x &amp; 1)  # lấy LSB</code></pre><pre><code class=\"language-python\">    return bits</code></pre><pre><code class=\"language-python\"># Rất chậm — chỉ có giá trị lý thuyết</code></pre><p>BBS cực chậm (phải tính modular exponentiation) — chỉ có giá trị lý thuyết. Nhưng đặt nền tảng cho CSPRNG hiện đại.</p><h3>3.2. Yarrow &amp; Fortuna (1999/2003)</h3><p>Bruce Schneier (cùng Niels Ferguson) thiết kế Yarrow (1999) rồi Fortuna (2003):</p><ul><li>Yarrow: Dùng bởi macOS/FreeBSD cho /dev/random (ban đầu)</li><li>Fortuna: Cải tiến — tự động quản lý nhiều entropy pool, tránh single point of failure</li><li>Cả hai dùng AES-256 làm block cipher nội bộ</li><p>macOS chuyển từ Yarrow sang Fortuna từ macOS 10.12 <span class=\"math-inline\" data-formula=\"Sierra\"><span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.6833em;\"></span><span class=\"mord mathnormal\" style=\"margin-right:0.05764em;\">S</span><span class=\"mord mathnormal\">i</span><span class=\"mord mathnormal\" style=\"margin-right:0.02778em;\">err</span><span class=\"mord mathnormal\">a</span></span></span></span></span>.</p></ul><h3>3.3. ChaCha20-based CSPRNG (2008–nay)</h3><p>Daniel J. Bernstein thiết kế ChaCha20 (biến thể của Salsa20). Hiện tại:</p><ul><li>Linux 4.8+ (2016): /dev/urandom dùng ChaCha20 thay LFSR</li><li>OpenBSD arc4random(): ChaCha20 từ 2013</li><li>Chrome/Node.js crypto.getRandomValues(): ChaCha20 trên nền OS</li><li>Rust rand crate: ChaCha12 mặc định</li><h2>4. Các Thuật Toán CSPRNG Hiện Đại</h2></ul><h3>4.1. ChaCha20 — Stream Cipher CSPRNG</h3><p>ChaCha20 là stream cipher hoạt động trên ma trận 4×4 <span class=\"math-inline\" data-formula=\"16 words, mỗi word 32-bit = 512 bits\"><span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:1.1257em;vertical-align:-0.1944em;\"></span><span class=\"mord\">16</span><span class=\"mord mathnormal\" style=\"margin-right:0.02691em;\">w</span><span class=\"mord mathnormal\" style=\"margin-right:0.02778em;\">or</span><span class=\"mord mathnormal\">d</span><span class=\"mord mathnormal\">s</span><span class=\"mpunct\">,</span><span class=\"mspace\" style=\"margin-right:0.1667em;\"></span><span class=\"mord mathnormal\">m</span><span class=\"mord accent\"><span class=\"vlist-t\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.9313em;\"><span style=\"top:-3em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord accent\"><span class=\"vlist-t\"><span class=\"vlist-r\"><span class=\"vlist\" style=\"height:0.6944em;\"><span style=\"top:-3em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"mord mathnormal\">o</span></span><span style=\"top:-3em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"accent-body\" style=\"left:-0.1944em;\"><span class=\"mord\">^</span></span></span></span></span></span></span></span><span style=\"top:-3.6134em;\"><span class=\"pstrut\" style=\"height:3em;\"></span><span class=\"accent-body\" style=\"left:-0.25em;\"><span class=\"mord\">~</span></span></span></span></span></span></span><span class=\"mord mathnormal\">i</span><span class=\"mord mathnormal\" style=\"margin-right:0.02691em;\">w</span><span class=\"mord mathnormal\" style=\"margin-right:0.02778em;\">or</span><span class=\"mord mathnormal\">d</span><span class=\"mord\">32</span><span class=\"mspace\" style=\"margin-right:0.2222em;\"></span><span class=\"mbin\">−</span><span class=\"mspace\" style=\"margin-right:0.2222em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.6944em;\"></span><span class=\"mord mathnormal\">bi</span><span class=\"mord mathnormal\">t</span><span class=\"mspace\" style=\"margin-right:0.2778em;\"></span><span class=\"mrel\">=</span><span class=\"mspace\" style=\"margin-right:0.2778em;\"></span></span><span class=\"base\"><span class=\"strut\" style=\"height:0.6944em;\"></span><span class=\"mord\">512</span><span class=\"mord mathnormal\">bi</span><span class=\"mord mathnormal\">t</span><span class=\"mord mathnormal\">s</span></span></span></span></span>:</p><pre><code class=\"language-javascript\">// ChaCha20 quarter-round (core operation)</code></pre><pre><code class=\"language-javascript\">function quarterRound(state, a, b, c, d) {</code></pre><pre><code class=\"language-javascript\">  state[a] += state[b]; state[d] ^= state[a]; state[d] = rotl32(state[d], 16);</code></pre><pre><code class=\"language-javascript\">  state[c] += state[d]; state[b] ^= state[c]; state[b] = rotl32(state[b], 12);</code></pre><pre><code class=\"language-javascript\">  state[a] += state[b]; state[d] ^= state[a]; state[d] = rotl32(state[d], 8);</code></pre><pre><code class=\"language-javascript\">  state[c] += state[d]; state[b] ^= state[c]; state[b] = rotl32(state[b], 7);</code></pre><pre><code class=\"language-javascript\">}</code></pre><pre><code class=\"language-javascript\">function rotl32(v, n) {</code></pre><pre><code class=\"language-javascript\">  return ((v &lt;&lt; n) | (v &gt;&gt;&gt; (32 - n))) &gt;&gt;&gt; 0;</code></pre><pre><code class=\"language-javascript\">}</code></pre><pre><code class=\"language-javascript\">// 20 rounds = 10 × (4 column rounds + 4 diagonal rounds)</code></pre><pre><code class=\"language-javascript\">// Input: 256-bit key + 96-bit nonce + 32-bit counter</code></pre><pre><code class=\"language-javascript\">// Output: 512 bits ngẫu nhiên mỗi block</code></pre><h3>4.2. AES-CTR-DRBG (NIST SP 800-90A)</h3><p>Chuẩn NIST cho CSPRNG trong chính phủ Mỹ và ngành tài chính:</p><pre><code class=\"language-python\"># Cấu trúc AES-CTR-DRBG simplified</code></pre><pre><code class=\"language-python\">class CTR_DRBG:</code></pre><pre><code class=\"language-python\">    def __init__(self, entropy, nonce):</code></pre><pre><code class=\"language-python\">        self.key = AES_key_from(entropy, nonce)  # 256-bit</code></pre><pre><code class=\"language-python\">        self.counter = 0</code></pre><pre><code class=\"language-python\">        self.reseed_counter = 0</code></pre><pre><code class=\"language-python\">    def generateself,numb​ytes:</code></pre><pre><code class=\"language-python\">        if self.reseed_counter &gt; 2**48:</code></pre><pre><code class=\"language-python\">            self.reseed()  # bắt buộc reseed</code></pre><pre><code class=\"language-python\">        blocks = []</code></pre><pre><code class=\"language-python\">        for _ in rangenumb​ytes//16+1:</code></pre><pre><code class=\"language-python\">            self.counter += 1</code></pre><pre><code class=\"language-python\">            blocks.appendAESe​ncrypt(self.key,self.counter)</code></pre><pre><code class=\"language-python\">            self.reseed_counter += 1</code></pre><pre><code class=\"language-python\">        return b''.joinblocks[:num_bytes]</code></pre><h3>4.3. HMAC-DRBG (RFC 6979)</h3><p>Dùng HMAC-SHA256 làm core. Đặc biệt quan trọng cho deterministic ECDSA (tránh lỗi reuse nonce):</p><pre><code class=\"language-plaintext\">// HMAC-DRBG pseudocode (RFC 6979)</code></pre><pre><code class=\"language-plaintext\">// K = HMAC key, V = value (both 256-bit)</code></pre><pre><code class=\"language-plaintext\">K = 0x00...00  (32 bytes)</code></pre><pre><code class=\"language-plaintext\">V = 0x01...01  (32 bytes)</code></pre><pre><code class=\"language-plaintext\">// Update:</code></pre><pre><code class=\"language-plaintext\">K = HMACK,V∣∣0x00∣∣seedm​aterial</code></pre><pre><code class=\"language-plaintext\">V = HMAC(K, V)</code></pre><pre><code class=\"language-plaintext\">K = HMACK,V∣∣0x01∣∣seedm​aterial</code></pre><pre><code class=\"language-plaintext\">V = HMAC(K, V)</code></pre><pre><code class=\"language-plaintext\">// Generate:</code></pre><pre><code class=\"language-plaintext\">V = HMAC(K, V)  → output</code></pre><pre><code class=\"language-plaintext\">// Mỗi lần generate xong phải update K, V</code></pre><h2>5. Ứng Dụng Cụ Thể</h2><p>CSPRNG được dùng trong mọi hệ thống bảo mật:</p><ul><li>TLS/SSL: Tạo session key, nonce, IV cho mỗi kết nối HTTPS</li><li>SSH: Tạo ephemeral key cho key exchange</li><li>OAuth/JWT: Tạo access token, refresh token</li><li>Mật khẩu: Tạo salt cho bcrypt/argon2, tạo mật khẩu ngẫu nhiên</li><li>Blockchain: Tạo private key (256-bit) cho ví Bitcoin/Ethereum</li><li>Gambling: Provably fair — seed được hash trước, reveal sau để chứng minh không gian lận</li><h2>6. API Trong Các Ngôn Ngữ</h2></ul><h3>JavaScript (Browser &amp; Node.js)</h3><pre><code class=\"language-javascript\">// Browser</code></pre><pre><code class=\"language-javascript\">const buffer = new Uint8Array(32);</code></pre><pre><code class=\"language-javascript\">crypto.getRandomValuesbuffer;</code></pre><pre><code class=\"language-javascript\">// Node.js</code></pre><pre><code class=\"language-javascript\">import { randomBytes, randomUUID } from \"node:crypto\";</code></pre><pre><code class=\"language-javascript\">const key = randomBytes(32); // 256-bit key</code></pre><pre><code class=\"language-javascript\">const uuid = randomUUID();   // v4 UUID (122 random bits)</code></pre><h3>Python</h3><pre><code class=\"language-python\">import secrets</code></pre><pre><code class=\"language-python\">import os</code></pre><pre><code class=\"language-python\"># Tạo token URL-safe</code></pre><pre><code class=\"language-python\">token = secrets.token_urlsafe(32)  # 256-bit</code></pre><pre><code class=\"language-python\"># Tạo số ngẫu nhiên trong range</code></pre><pre><code class=\"language-python\">pin = secrets.randbelow10​000​00  # 6-digit PIN</code></pre><pre><code class=\"language-python\"># Bytes thô từ OS</code></pre><pre><code class=\"language-python\">raw = os.urandom(32)</code></pre><pre><code class=\"language-python\"># ⚠️ KHÔNG dùng `random` module cho bảo mật!</code></pre><pre><code class=\"language-python\">import random  # ❌ dùng Mersenne Twister — KHÔNG CSPRNG</code></pre><h3>Rust</h3><pre><code class=\"language-rust\">use rand::rngs::OsRng;</code></pre><pre><code class=\"language-rust\">use rand::RngCore;</code></pre><pre><code class=\"language-rust\">fn main() {</code></pre><pre><code class=\"language-rust\">    let mut key = [0u8; 32];</code></pre><pre><code class=\"language-rust\">    OsRng.fill_bytes(&amp;mut key); // /dev/urandom</code></pre><pre><code class=\"language-rust\">    println!(\"256-bit key: {:?}\", key);</code></pre><pre><code class=\"language-rust\">    // Hoặc dùng getrandom crate (lower-level)</code></pre><pre><code class=\"language-rust\">    let mut buf = [0u8; 16];</code></pre><pre><code class=\"language-rust\">    getrandom::getrandom(&amp;mut buf).expect(\"failed\");</code></pre><pre><code class=\"language-rust\">}</code></pre><h3>Java</h3><pre><code class=\"language-java\">import java.security.SecureRandom;</code></pre><pre><code class=\"language-java\">SecureRandom csprng = SecureRandom.getInstanceStrong();</code></pre><pre><code class=\"language-java\">byte[] key = new byte[32];</code></pre><pre><code class=\"language-java\">csprng.nextByteskey; // 256-bit random key</code></pre><pre><code class=\"language-java\">// Hoặc sinh số trong range</code></pre><pre><code class=\"language-java\">int pin = csprng.nextInt10​000​00; // 6-digit PIN</code></pre><h3>C <span class=\"math-inline\" data-formula=\"Linux\"><span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.6833em;\"></span><span class=\"mord mathnormal\">L</span><span class=\"mord mathnormal\">in</span><span class=\"mord mathnormal\">ux</span></span></span></span></span></h3><pre><code class=\"language-c\">#include &lt;sys/random.h&gt;</code></pre><pre><code class=\"language-c\">#include &lt;stdio.h&gt;</code></pre><pre><code class=\"language-c\">int main() {</code></pre><pre><code class=\"language-c\">    unsigned char key[32];</code></pre><pre><code class=\"language-c\">    // getrandom() — Linux 3.17+ (glibc 2.25+)</code></pre><pre><code class=\"language-c\">    ssize_t ret = getrandom(key, sizeof(key), 0);</code></pre><pre><code class=\"language-c\">    if ret!=sizeof(key) {</code></pre><pre><code class=\"language-c\">        perror(\"getrandom failed\");</code></pre><pre><code class=\"language-c\">        return 1;</code></pre><pre><code class=\"language-c\">    }</code></pre><pre><code class=\"language-c\">    // key now contains 256 bits of CSPRNG output</code></pre><pre><code class=\"language-c\">    return 0;</code></pre><pre><code class=\"language-c\">}</code></pre><h2>7. Lỗi Bảo Mật Nổi Tiếng</h2><ul><li>Debian OpenSSL (2008 — CVE-2008-0166): Comment nhầm 2 dòng code → entropy chỉ còn PID (~32,000 giá trị) → TẤT CẢ key SSL trên Debian trong 2 năm đều có thể brute-force</li><li>Sony PS3 ECDSA (2010): Dùng static k <span class=\"math-inline\" data-formula=\"nonce\"><span class=\"katex\"><span class=\"katex-html\" aria-hidden=\"true\"><span class=\"base\"><span class=\"strut\" style=\"height:0.4306em;\"></span><span class=\"mord mathnormal\">n</span><span class=\"mord mathnormal\">o</span><span class=\"mord mathnormal\">n</span><span class=\"mord mathnormal\">ce</span></span></span></span></span> cho ECDSA → lộ private key, jailbreak toàn bộ PS3</li><li>Android SecureRandom (2013): Thiếu entropy initialization → ví Bitcoin trên Android bị trộm</li><li>Dual_EC_DRBG (2013): NSA cài backdoor trong chuẩn NIST — Kleptographic attack</li></ul>","tags":["Công nghệ","Khoa học","Lập trình","Thuật toán"],"author":"Quản trị viên","publishedAt":"2026-04-04T07:48:10.994Z","updatedAt":"2026-10-14T16:33:59.947Z","published_at":"2026-04-04T07:48:10.994Z","updated_at":"2026-10-14T16:33:59.947Z","view_count":423,"canonical":"https://wiki.quizzman.com/wiki/csprng-la-gi-lich-su-thuat-toan-ung-dung-sinh-so-ngau-nhien-mat-ma","url":"https://wiki.quizzman.com/wiki/csprng-la-gi-lich-su-thuat-toan-ung-dung-sinh-so-ngau-nhien-mat-ma","markdownUrl":"https://wiki.quizzman.com/api/articles/csprng-la-gi-lich-su-thuat-toan-ung-dung-sinh-so-ngau-nhien-mat-ma.md","apiUrl":"https://wiki.quizzman.com/api/articles/csprng-la-gi-lich-su-thuat-toan-ung-dung-sinh-so-ngau-nhien-mat-ma"}