「Javaで乱数を生成する」というタイトルだが、生成できるのは疑似乱数だ。今日は「Javaで乱数を生成する(1)」で説明した「疑似乱数生成器がどのように疑似乱数を生成するのか」について、Javaではどのように実装すればよいか説明する。
Javaでは、疑似乱数生成器として“java.util.Random”と“java.security.SecureRandom”が用意されている(SecureRandomクラスはRandomクラスのサブクラス)。
Randomクラスは、線形合同法*1を用いており、出力された値から内部状態が推測可能(次に出力される値が推測可能)な疑似乱数生成器である。なので、セキュリティ用途では使えない。
SecureRandomクラスは、内部でハッシュ演算を行っており、出力された値から内部状態が推測困難な疑似乱数生成器である。セキュリティ用途では、こちらを用いなければならない。
後は、推測困難なシードを用いて、疑似乱数生成器を初期化すればよい。
例えば、128バイトの疑似乱数を“2つだけ”得たい場合には、次のように実装すればよい。
// 推測困難なシードを用意する。 byte[] seed = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* (途中略) */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; // シードを用いて、疑似乱数生成器を初期化する。 Random prng = new SecureRandom(seed); // 疑似乱数を生成する。 byte[] results1 = new byte[128]; prng.nextBytes(results1); // 疑似乱数を生成する。 byte[] results2 = new byte[128]; prng.nextBytes(results2);
なるほど。
しかし、このプログラムは、全くもって実用的ではない。このプログラムを2回実行すると、2回とも同じ疑似乱数が得られるからだ*2。では、実際には、どのように疑似乱数を生成すればよいのだろうか?
私は、難しいことはわからないので、Apache Tomcatに教えてもらおうと思う。
(つづく)