Skip to content

コラム: 擬似乱数生成器 ​

擬似乱数生成器について ​

PRNG(Pseudo-Random Number Generator:擬似乱数生成器)は、シードと呼ぶ初期値から、決まった計算で乱数のように見える数列を作るアルゴリズムです。NIST SP 800-22は、PRNGを次のように定義しています。

A deterministic algorithm which, given a truly random binary sequence of length k, outputs a binary sequence of length l >> k which appears to be random. The input to the generator is called the seed, while the output is called a pseudorandom bit sequence.

訳)長さkの真の乱数のビット列を与えると、長さl(l >> k)の、乱数のように見えるビット列を出力する決定論的なアルゴリズム。生成器への入力をシード、出力を擬似乱数ビット列と呼ぶ。

引用元: NIST SP 800-22 Rev. 1a §1.2 Definitions

決定論的なアルゴリズムであることと、長さkのシードからずっと長い長さlの数列を出力できることが、PRNGの2つの性質です。

シードより長い出力(引き伸ばし)シード擬似乱数生成器5e 9b 02 c7 41 d8 6a f3 0e 77 b4 19 …同じシード同じ出力(決定論的)シード擬似乱数生成器5e 9b 02 c7 41 d8 6a f3 0e 77 b4 19 …

擬似乱数生成器の2つの性質

2つの性質は、どちらもストリーム暗号に欠かせません。同じシードからは必ず同じ数列が出るので、送信側と受信側は、同じ鍵から同じ鍵ストリームを作れます。短いシードから長い数列を作れるので、16バイトの鍵からでも平文と同じ長さの鍵ストリームを作れ、鍵を繰り返して使わずに済みます。

表1は、プログラミング言語の標準ライブラリにあるPRNGの例です。

PRNG使用例
線形合同法[1]Javaのjava.util.Random
メルセンヌ・ツイスタ[2]Pythonのrandomモジュール
xorshift128+[3]JavaScriptエンジンV8のMath.random

PRNGの例

暗号的に安全な擬似乱数生成器について ​

PRNGの出力は、乱数のように見えても暗号に使えるとは限りません。表1のPRNGは、どれも暗号用ではありません。たとえば、メルセンヌ・ツイスタでは、攻撃者が連続した624個の出力から内部状態を復元でき、その先の出力をすべて計算できます。Goでも、math/randパッケージは暗号用ではなく、暗号にはcrypto/randパッケージを使います。

CSPRNG(Cryptographically Secure Pseudo-Random Number Generator:暗号論的擬似乱数生成器)は、暗号に使えるPRNGです。表2はCSPRNGの例です。

CSPRNG使用例
ChaCha20Linuxのgetrandom、OpenBSDのarc4random
NIST SP 800-90Aで定めた生成器OpenSSLのRAND_bytes
AES-CTRAES-GCMの鍵ストリーム

CSPRNGの例

CSPRNGには、PRNGの2つの性質に加えて、以下2つの性質があります。

1. 次のビットを予測できない ​

次ビット検定[4]は、出力の先頭kビットを知っている攻撃者が、k+1ビット目を予測できるかを調べる検定です。 CSPRNGの1つ目の性質は、次ビット検定に合格することです。 次ビット検定に合格するとは、図2のように、攻撃者にとって、k+1ビット目が1か0かを1/2より高い確率で当てる現実的な方法がないことです。

擬似乱数生成器の出力110100101110?攻撃者が知っている先頭kビットk+1ビット目1か0かを、1/2より高い確率で当てられない

次ビット検定

SP 800-22も、暗号に使う擬似乱数に、次の出力を予測できないことを求めています。

Random and pseudorandom numbers generated for cryptographic applications should be unpredictable. In the case of PRNGs, if the seed is unknown, the next output number in the sequence should be unpredictable in spite of any knowledge of previous random numbers in the sequence. This property is known as forward unpredictability.

訳)暗号に使うために生成する乱数と擬似乱数は、予測できないものであるべきである。PRNGの場合、シードが分からなければ、数列の前の乱数をどれだけ知っていても、数列の次の出力は予測できないものであるべきである。この性質を前方予測不可能性(forward unpredictability)と呼ぶ。

引用元: NIST SP 800-22 Rev. 1a §1.1.2 Unpredictability

AES-GCMでは、AESが鍵ストリームを作るCSPRNGとなります。AES-GCMの鍵ストリームは、1ずつ増えるカウンタをAESで暗号化し、出力をつなげたものです。

keystream=AES(key,ctr)∥AES(key,ctr+1)∥⋯

keystream:鍵ストリームkey:鍵ctr:1ずつ増えるカウンタ

AESの出力から鍵や続きの出力を求める現実的な方法は、見つかっていません。攻撃者は、HTTPのレスポンスの先頭のように平文の一部を推測して鍵ストリームの一部を得ても、残りの鍵ストリームを予測できません。

2. 状態侵害拡張攻撃への耐性がある ​

PRNGの出力は、内部状態から計算した値です。内部状態は、出力のたびに次の値に変わります。状態侵害拡張攻撃[5]は、漏れた内部状態を手がかりに、攻撃者がほかの出力を求める攻撃です。状態侵害拡張攻撃への耐性には、漏洩より前の出力を守ることと、漏洩より後の出力を守ることの2つがあります。

DRBG(Deterministic Random Bit Generator:決定論的乱数ビット生成器)は、NIST SP 800-90Aが暗号用に定めたPRNGです。SP 800-90Aでの2つの耐性の定義は、次のとおりです。

Backtracking resistance means that a compromise of the DRBG internal state has no effect on the security of prior outputs.

(中略)

Prediction resistance means that a compromise of the DRBG internal state has no effect on the security of future DRBG outputs.

訳)backtracking resistanceとは、DRBGの内部状態が侵害されても、侵害より前の出力の安全性に影響しないことである。(中略)prediction resistanceとは、DRBGの内部状態が侵害されても、侵害より後のDRBGの出力の安全性に影響しないことである。

引用元: NIST SP 800-90A Rev. 1 §8.8 Prediction Resistance and Backtracking Resistance

図3は、状態侵害拡張攻撃への耐性を持つPRNGの例です。内部状態の更新は逆にたどれない計算なので、内部状態3が漏れても、攻撃者は出力1と出力2を遡って求められません。攻撃者は内部状態3から出力3を計算できますが、内部状態4は内部状態3に予測しにくい値を混ぜた値なので、出力4以降は求められません。

内部状態1出力1内部状態2出力2内部状態3出力3内部状態4出力4更新更新更新混ぜて更新予測しにくい値攻撃者に漏れる…遡って求められない計算できる求められない

状態侵害拡張攻撃への耐性

OSのCSPRNGは、ハードウェアから集めた予測しにくい値を、内部状態に混ぜ続ける仕組みになっています。

ストリーム暗号では、鍵とカウンタがそのまま内部状態です。内部状態が漏れることは鍵が漏れることと同じなので、攻撃者は過去の暗号文も復号できます。状態侵害拡張攻撃への耐性が意味を持つのは、鍵や乱数を作るためのCSPRNGです。

TLSでCSPRNGを使う値 ​

TLSでCSPRNGを使う値は、表3の3つです。

値作り方
ClientHelloとServerHelloのrandomOSのCSPRNGから読む
X25519の秘密鍵OSのCSPRNGから読む
レコードを暗号化する鍵ストリーム鍵とnonceをシードにして、AESやChaCha20で作る

TLSでCSPRNGを使う値

RFC 9846は、実装者向けの注意をまとめた付録Cで、randomや秘密鍵のような乱数を作るにはCSPRNGが必要だと述べています。

TLS requires a cryptographically secure pseudorandom number generator (CSPRNG).

訳)TLSは、暗号論的擬似乱数生成器(CSPRNG)を必要とする。

引用元: RFC 9846 §C.1 Random Number Generation and Seeding

randomは平文で送る値ですが、表3のとおり、秘密鍵と同じOSのCSPRNGから読んだ値です。出力から内部状態を求められる生成器では、攻撃者がrandomから秘密鍵まで計算できる場合があります。

鍵ストリームは、送信側と受信側が同じ鍵とnonceから同じ値を作り直す必要があるので、OSのCSPRNGではなく、AESやChaCha20で作る値です。

本書のクライアントは、randomと秘密鍵をcrypto/randパッケージで作り、レコードの暗号化にAES-GCMを使います。


  1. D. E. Knuth, "The Art of Computer Programming, Volume 2: Seminumerical Algorithms", 3rd ed., Addison-Wesley, 1997. ↩︎

  2. M. Matsumoto, T. Nishimura, "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on Modeling and Computer Simulation, 1998. DOI ↩︎

  3. S. Vigna, "Further Scramblings of Marsaglia's xorshift Generators", Journal of Computational and Applied Mathematics, 2017. DOI ↩︎

  4. A. C. Yao, "Theory and Application of Trapdoor Functions", 23rd Annual Symposium on Foundations of Computer Science, 1982. DOI ↩︎

  5. J. Kelsey, B. Schneier, D. Wagner, C. Hall, "Cryptanalytic Attacks on Pseudorandom Number Generators", Fast Software Encryption, 1998. DOI ↩︎