web-dev-qa-db-ja.com

Java SecureRandomはブロックしませんか?方法?

Linuxカーネルエントロピープールがエントロピーを使い果たすと、/ dev/randomからの読み取りがブロックされることが経験からわかっています。また、Linuxで実行する場合、Java.security.SecureRandomは/ dev/randomをエントロピーソースとして使用するため、カーネルエントロピープールがエントロピーを使い果たすとブロックすることを述べた多くの記事やブログエントリを見てきました。

ただし、SecureRandomをブロックする実験を行うことはできません。逆に、/ dev/randomから読み取ってブロックする単純なbashワンライナーを取得するのは簡単なようです。

これが私がこれらの実験に使用しているJavaコードです:

import Java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr = new SecureRandom();
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}

1,000,000を超えるランダムな32ビット整数を生成します。それは2 ^(20 + log2(32))= 2 ^ 25ビットまたは2 ^ 22(400万強)バイトのエントロピーになるはずですよね?ただし、ブロックすることはありません。マウスを小刻みに動かしてもしなくても、常に約1.2秒で終了します。

私が使用したbashワンライナーは次のとおりです。

head -c 100 /dev/random | xxd

これは簡単にブロックされます。マウスとキーボードに手を近づけない限り、数分間何もせずに座ったままになります。そして、私は100バイトのエントロピーのみを求めています。

きっとここに何かが足りない。誰かが何が起こっているのか説明できますか?

ありがとう!

22
user1483512

OpenJDKとSunはどちらも、少なくとも私がテストしたマシン(Debian上のOpenJDK JRE 6b27とSun JRE 6.26でAMD64をスクイーズしたマシン)では、/dev/urandomではなく/dev/randomから読み取ります。何らかの理由で、どちらも/dev/randomも開きますが、そこから読み取ることはありません。そのため、あなたが読んだブログ記事は誤っているか、私のバージョンとは異なるバージョンに適用されていました(そして明らかに、あなたのバージョンです)。

トレースすることで、/dev/randomまたは/dev/urandomのどちらから読み取るかを確認できます。

strace -o a.strace -f -e file Java A

トレースの関連部分を探します。

21165 open("/dev/random", O_RDONLY)     = 6
…
21165 open("/dev/urandom", O_RDONLY)    = 7
…
21165 read(7, "\322\223\211\262Zs\300\345\3264l\254\354[\6wS\326q@", 20) = 20
…

心配しないでください /dev/urandom は、暗号化にはまったく問題ありません。

JavaのSecureRandom doesは/ dev/randomを使用しますが、ほんの少しだけです。

具体的には、明示的にSecureRandom.generateSeed()を呼び出すか、最初のnextInt()を呼び出すことによって、シード情報を生成するときにのみ使用します。

したがって、bashの例を繰り返すには、次のようにすることができ、ブロックする必要があります。

import Java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr;
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            sr = new SecureRandom();
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}
9
diedthreetimes

古いスレッドを存続させるだけでなく、この背後にある長いストーリーの重要な部分を見逃している人もいるでしょう... = dev = urandom from Javaバージョン1.4からバージョン1.7。以下のリンクを参照してください。

http://bugs.Java.com/view_bug.do?bug_id=6202721

http://bugs.Java.com/view_bug.do?bug_id=470509

私が知っていることのために、これは最終的にJava 8で対処されています: https://docs.Oracle.com/javase/8/docs/technotes/guides /security/enhancements-8.html

SHA1PRNGおよびNativePRNGは、Java.securityファイルのSecureRandomシードソースプロパティを適切に尊重するように修正されました。 (file:/// dev/urandomおよびfile:/ dev /./ urandomを使用するあいまいな回避策は不要になりました。)

4
ozys

$Java_HOME/lib/security/Java.securitysecurerandom.sourceプロパティは、SecureRandomを使用するときに使用するデバイスを指定します。デフォルト値は/dev/urandomです。つまり、Javaがブロックすることはありません。

トピックへの新規参入者にとって、/dev/urandom/dev/randomの特別なバージョンであり、使用可能な場合は/dev/randomからの真のエントロピーを使用し、使用可能な場合は疑似ランダムデータが真のエントロピーをシードします。

ヘッドレスでは、VMおよびクラウド環境では、 http://random.org などの外部ソースからランダムにシードすることをお勧めします

3

最近のヴィンテージLinux(過去6年間など)では、/ dev/random(ブロッキング)と/ dev/urandom(非ブロッキング)の計算量の差はごくわずかです。生のエントロピーは、乱数ジェネレーターによって洗浄され、両方のデバイスが同じビットを使用します。唯一の違いは、/ dev/randomにレートリミッターがあり、再シードせずに長時間実行し過ぎないようにすることです。レートの見積もり自体はかなり議論の余地があります。

これは http://www.2uo.de/myths-about-urandom/ で説明されており、セッションキーの暗号化アルゴリズムをシードするのに/ dev/urandomで十分であるという点を示しています。頻繁に呼び出さない場合は、どちらも同じ品質またはほぼ同じ品質である必要があります。

1000以上の同時SSL接続(セッションキー)を作成する必要のあるWebクローラーを実行しているときに/ dev/randomを介してブロックするのを見てきました。そうです、/ dev/urandomに切り替えました。長期間保持される公開鍵と秘密鍵のペアの大量生成(まれな状況)には、カスタムエントロピーデバイスが最適です。

3
Paul Baclace