[java] SecureRandom のアルゴリズムの選択について
前提
Java SE 8 + Linux 前提です。
Java で暗号的に安全な乱数をえる
Java で暗号的に安全な乱数を得るには SecureRandom クラスを利用します。 SecureRandom ではいくつかの乱数生成アルゴリズムをサポートしています。
各プラットフォームでもっとも安全な SecureRandom の実装は ${JAVA_HOME}/jre/lib/security/java.security
の securerandom.strongAlgorithms という項目に書いてあります。 SecureRandom#getInstanceStrong()
で取得できるのはこれです。
インスタンスの取得方法
new SecureRandom()
でデフォルト実装が得られます- OSX や linux では
NativeBlocking です(SHA1PRNGの場合もある)NativePRNG です SecureRandom#getInstance(name)
で名前を指定して実装を得られますSecureRandom#getInstanceStrong()
で、プラットフォームでもっとも強力な実装が得られます- OSX や linux では NativePRNGBlocking です
- /dev/random を利用します
各アルゴリズムの詳細
実装は以下のようになっています。
SHA1PRNG (Initial seeding is currently done via a combination of system attributes and the java.security entropy gathering device)
NativePRNG (nextBytes() uses /dev/urandom, generateSeed() uses /dev/random)
NativePRNGBlocking (nextBytes() and generateSeed() use /dev/random)
NativePRNGNonBlocking (nextBytes() and generateSeed() use /dev/urandom)
http://docs.oracle.com/javase/jp/8/technotes/guides/security/SunProviders.html
NativePRNGBlocking は /dev/random から取得するので、遅いです。 あまり利用されていない開発サーバーなどでは 30 秒ぐらいかかります。 鍵の生成などにはこれを利用するべきですが、ちょっとしたトークンの生成などに利用すると、めっちゃ遅くてなけます。
トークンの生成等には NativePRNG または NativePRNGNonBlocking を利用すれば十分かと。
ちなみに、NativePRNGBlocking と NativePRNGNonBlocking は最近導入されたようです。
For UNIX-like platforms, two new implementations were introduced which provide blocking and non-blocking behavior: NativePRNGBlocking and NativePRNGNonBlocking. http://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html
securerandom.source の変更について
インターネットを見ていると、securerandom.source
を変更して /dev/urandom を見るようにしろ、という記述を見かけますが、これは Java 8 の世界では間違ったやり方だと私は思います。
NativePRNGNonBlocking を利用するように実装を変更するのが正しいアプローチだと私は考えます。
tips
/dev/random
がどんどん出てくるかどうかは head -n 1 /dev/random
で調べることができる。
まとめ
とりあえず弱いよりは強い方がいいだろってことで SecureRandom#getInstanceStrong()
を呼んだりしてるとサービスが刺さる。
参考文献
- http://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#SecureRandom
- http://docs.oracle.com/javase/jp/8/technotes/guides/security/StandardNames.html#SecureRandom
- http://docs.oracle.com/javase/jp/8/technotes/guides/security/SunProviders.html
- http://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html
2016-05-12 追記
デフォルトの SecureRandom の Algorithm を確認する方法
import java.security.SecureRandom;
public class Hoge {
public static void main(String[] args) {
SecureRandom sr = new SecureRandom();
System.out.println(sr.getAlgorithm());
}
}