質問

Java で暗号的に強力な乱数が必要な場合は、次を使用します。 SecureRandom. 。残念ながら、 SecureRandom 非常に遅くなる可能性があります。使用する場合 /dev/random Linux では、十分なエントロピーが蓄積されるまでの待機がブロックされる可能性があります。パフォーマンスのペナルティを回避するにはどうすればよいでしょうか?

誰か使った人いますか 珍しい数学 この問題の解決策として?

このパフォーマンスの問題が JDK 6 で解決されたことを確認できる人はいますか?

役に立ちましたか?

解決

真のランダムデータが必要な場合、残念ながらそれを待つ必要があります。これには、 SecureRandom PRNGのシードが含まれます。 Uncommon Mathsは、インターネットに接続して特定のWebサイトからシードデータをダウンロードすることはできますが、 SecureRandom より速く真のランダムデータを収集することはできません。私の推測では、これが利用可能な場合、 / dev / random よりも高速になる可能性は低いと思われます。

PRNGが必要な場合は、次のようにします:

SecureRandom.getInstance("SHA1PRNG");

サポートされる文字列は、 SecureRandom SPIプロバイダーによって異なりますが、 Security.getProviders()および Provider.getService()

SunはSHA1PRNGが好きなので、広く利用可能です。 PRNGが進むにつれて特に高速ではありませんが、PRNGはエントロピーの物理的な測定をブロックするのではなく、単に計算する数値になります。

例外は、データを取得する前に setSeed()を呼び出さない場合、PRNGは next()を初めて呼び出したときに一度シードされることです。 nextBytes()。通常、システムからのかなり少量の真のランダムデータを使用してこれを行います。この呼び出しはブロックする可能性がありますが、乱数のソースを「現在の時刻とPIDをハッシュし、27を追加し、最高の結果を期待する」よりもはるかに安全です。ただし、ゲームに必要なのが乱数だけである場合、またはテストの目的で同じシードを使用して将来ストリームを繰り返し可能にする場合は、安全でないシードが引き続き有用です。

他のヒント

次のコマンドを使用して、Linuxでより高速だが少し安全性の低い/ dev / urandomを選択できるはずです:

-Djava.security.egd=file:/dev/urandom

ただし、これはJava 5以降では機能しません( Javaバグ6202721 )。推奨される回避策は次を使用することです:

-Djava.security.egd=file:/dev/./urandom

(余分な /./ に注意してください)

Linuxでは、 SecureRandom のデフォルトの実装は NativePRNG (ソースコードこちら)、非常に遅い傾向があります。 Windowsでは、デフォルトは SHA1PRNG です。他の人が指摘したように、明示的に指定するとLinuxでも使用できます。

NativePRNG SHA1PRNG およびUncommons Mathsの AESCounterRNG は、オペレーティングシステムから継続的にエントロピーを受信するという点で( / dev / urandom から読み取ることにより)。他のPRNGは、シード後に追加のエントロピーを取得しません。

AESCounterRNGは、 SHA1PRNG よりも約10倍高速です。IIRC自体は、 NativePRNG よりも2〜3倍高速です。

初期化後にエントロピーを取得するより高速なPRNGが必要な場合は、 Fortuna 。 Fortuna実装のコアPRNGはAESCounterRNGで使用されるものと同じですが、エントロピープーリングと自動再シードの洗練されたシステムもあります。

多くのLinuxディストリビューション(ほとんどがDebianベース)は、エントロピーに / dev / random を使用するようにOpenJDKを構成します。

/ dev / random は定義上低速です(ブロックすることもできます)。

ここから、ブロックを解除する方法に関する2つのオプションがあります。

  1. エントロピーを改善する、または
  2. ランダム性の要件を減らします。

オプション1、エントロピーの改善

/ dev / random にエントロピーを追加するには、 haveged デーモン。 HAVEGEエントロピーを継続的に収集するデーモンであり、特別なハードウェアを必要とせず、CPU自体とクロックのみを必要とするため、仮想化環境でも動作します。

Ubuntu / Debianの場合:

apt-get install haveged
update-rc.d haveged defaults
service haveged start

RHEL / CentOSの場合:

yum install haveged
systemctl enable haveged
systemctl start haveged

オプション2.ランダム性の要件を減らす

何らかの理由で上記の解決策が役に立たない場合、または暗号的に強いランダム性を気にしない場合は、代わりに / dev / urandom に切り替えることができます。 / p>

グローバルに実行するには、デフォルトのJavaインストールで jre / lib / security / java.security ファイルを編集して、 / dev / urandom を使用します(別の< href = "https://bugs.openjdk.java.net/browse/JDK-6202721" rel = "noreferrer">バグ / dev /./ urandom code>)。

これに似ています:

#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom

コマンドラインで指定する必要はありません。


注:暗号化を行う場合、良好なエントロピーを必要にします。適切な事例- Android PRNGの問題により、ビットコインウォレットのセキュリティが低下しました。

同様に、ヘッドレスDebianサーバーで SecureRandom を一度に約25秒間ブロックすると、同様の問題が発生しました。 haveged デーモンをインストールして、 / dev / random が確実に追加されるようにします。ヘッドレスサーバーでは、必要なエントロピーを生成するためにこのようなものが必要です。 SecureRandom への呼び出しには、おそらくミリ秒かかります。

本当に「暗号的に強力」な場合ランダム性の場合、強力なエントロピーソースが必要です。 / dev / random は、システムイベントがエントロピー(ディスク読み取り、ネットワークパケット、マウスの動き、キーの押下など)を収集するまで待機する必要があるため、低速です。

より高速なソリューションは、ハードウェア乱数ジェネレーターです。マザーボードには既に1つが組み込まれている場合があります。 hw_randomのドキュメントを参照して、把握しているかどうかを確認してください。どうやって使うのですか。 rng-toolsパッケージには、ハードウェアで生成されたエントロピーを / dev / random に供給するデーモンが含まれています。

システムでHRNGを使用できず、パフォーマンスのためにエントロピーの強度を犠牲にする場合、 / dev / random のデータを使用して適切なPRNGをシードし、 PRNGが大部分の作業を行います。 SP800-90 実装は簡単です。

同じ問題に直面しました。適切な検索用語でいくつかのグーグル検索を行った後、 DigitalOcean

havegedは、セキュリティを犠牲にすることなく解決できる可能性があります。

ここで記事の関連部分を引用するだけです。

  

HAVEGE原則に基づき、以前はその関連に基づいていました   ライブラリ、havegedでは、のバリエーションに基づいてランダム性を生成できます   プロセッサでのコード実行時間。ほぼ不可能だから   実行するのに同じ正確な時間を要する1つのコード   同じハードウェア上の同じ環境、単一の実行のタイミング   または、複数のプログラムがランダムソースのシードに適している必要があります。の   haveged実装は、システムのランダムソース(通常は   / dev / random)プロセッサのタイムスタンプカウンターの違いを使用   (TSC)ループを繰り返し実行した後

havegedのインストール方法

この記事の手順に従ってください。 https:// www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged

こちら

に投稿しました

リカレントアルゴリズムの初期化ソースとしてセキュアランダムを使用します。 UncommonMathの代わりにメルセンヌツイスターを一括作業に使用できます。

http://en.wikipedia.org/wiki/Mersenne_twister

今すぐ更新してから、初期化に使用するセキュアランダムを確認してください。たとえば、クライアントごとに1つのmersenne twister擬似ランダムジェネレーターを使用して、クライアントごとに1つのセキュアランダムを生成し、十分な高度のランダム化を取得できます

Java 8を使用すると、Linuxで SecureRandom.getInstanceStrong()を呼び出すと、 NativePRNGBlocking アルゴリズムが得られることがわかりました。これにより、数秒間ブロックされ、数バイトのソルトが生成されます。

代わりに NativePRNGNonBlocking を明示的に要求するように切り替えましたが、名前から予想されるように、ブロックされなくなりました。これがセキュリティにどのような影響を与えるかはわかりません。おそらく、非ブロッキングバージョンでは、使用されているエントロピーの量を保証できません。

更新:OK、この優れた説明

簡単に言えば、ブロックを回避するには、 new SecureRandom()を使用します。これは / dev / urandom を使用します。これはブロックせず、基本的に / dev / random と同じくらい安全です。投稿から:&quot; / dev / randomを呼び出したいのは、マシンが最初に起動し、エントロピーがまだ蓄積されていないときだけです。

SecureRandom.getInstanceStrong()は最も強力なRNGを提供しますが、大量のブロッキングが影響しない状況でのみ安全に使用できます。

/ dev / random で参照した問題は、 SecureRandom アルゴリズムではなく、それが使用するランダム性のソースにあります。 2つは直交しています。 2つのうちどちらが遅くなっているのかを把握する必要があります。

リンクした一般的でない数学のページでは、ランダム性の原因に取り組んでいないことが明示的に記載されています。

BouncyCastleなどのさまざまなJCEプロバイダーを試して、 SecureRandom の実装が高速であるかどうかを確認できます。

簡単な検索は、デフォルトを置き換えるLinuxパッチも明らかにします。 Fortunaによる実装。これについてはあまり知りませんが、調査してください。

また、実装が不十分な SecureRandom アルゴリズムやランダム性ソースを使用することは非常に危険ですが、 SecureRandomSpi 。プロバイダに署名させるには、Sunとのプロセスを経る必要がありますが、実際には非常に簡単です。暗号ライブラリに関する米国の輸出制限を認識していることを示すフォームをFAXで送信するだけです。

私はこの問題に自分自身で遭遇したことはありませんが、プログラムの起動時にスレッドを生成して、すぐにシードを生成しようとしてから死にます。ランダムに呼び出すメソッドは、そのスレッドが生きている場合はそのスレッドに参加するため、プログラムの実行の非常に早い段階で最初の呼び出しがブロックされるだけです。

私の経験では、PRNGの初期化が遅いだけで、その後のランダムデータの生成はありません。より熱心な初期化戦略を試してください。作成に費用がかかるため、シングルトンのように扱い、同じインスタンスを再利用します。 1つのインスタンスのスレッド競合が多すぎる場合は、プールするか、スレッドをローカルにします。

乱数生成について妥協しないでください。弱点があると、すべてのセキュリティが危険にさらされます。

COTSアトミックディケイベースのジェネレーターはあまりありませんが、大量のランダムデータが本当に必要な場合は、いくつかの計画があります。 HotBitsなど、常に興味深いものを見ることができるサイトの1つは、 John WalkerのFourmilabです。

RNGの要件について明確にする必要があるようです。最も強力な暗号化RNG要件(私が理解しているように)は、それらを生成するために使用されるアルゴリズムを知っていて、以前に生成されたすべての乱数を知っていても、で生成された乱数のいずれについても有用な情報を取得できないことです将来、非現実的な量の計算能力を費やすことなく。

このランダム性の完全な保証が必要ない場合は、おそらく適切なパフォーマンスのトレードオフがあります。私はダンダイアーの応答に同意する傾向があります。 Uncommons-MathsのAESCounterRNG、またはFortuna(その著者の1人は、暗号の専門家であるBruce Schneierです)。どちらも使用したことはありませんが、アイデアは一見信頼できるように見えます。

私は、最初のランダムシードを定期的に(たとえば、1日または1時間に1回など)生成できる場合、高速ストリーム暗号を使用して、連続するチャンクから乱数を生成できると考えます ストリーム(ストリーム暗号がXORを使用する場合、nullのストリームを渡すか、XORビットを直接取得します)。 ECRYPTの eStream プロジェクトには、パフォーマンスベンチマークを含む多くの優れた情報があります。これは、あなたがそれを補充する時点の間でエントロピーを維持しないので、誰かがあなたが乱数の1つとあなたが使用したアルゴリズムを知っていれば、技術的には、多くの計算能力で、ストリーム暗号を破って、内部状態を推測して、将来の乱数を予測できるようにします。ただし、そのリスクとその結果がエントロピーを維持するコストを正当化するのに十分かどうかを判断する必要があります。

編集:ここにいくつかの RNGの暗号コースノートネット上でこのトピックに非常に関連性の高いものを見つけました。

ハードウェアがサポートしている場合は試してください Java RdRand ユーティリティの使用 その著者は私です。

Intel に基づいています RDRAND 命令よりも約 10 倍高速です SecureRandom また、大規模な実装でも帯域幅の問題は発生しません。


この実装は、命令を提供する CPU (つまり、いつ rdrand プロセッサフ​​ラグが設定されます)。を介して明示的にインスタンス化する必要があります。 RdRandRandom() コンストラクタ;具体的ではない Provider が実装されました。

他に注目すべきものは、ファイルlib / security / java.securityのプロパティsecurerandom.sourceです。

/ dev / randomではなく/ dev / urandomを使用すると、パフォーマンスが向上する場合があります。乱数の品質が重要な場合、セキュリティを損なうような妥協をしないでください。

Apache commons Mathプロジェクトを試すことができます。これには、よく知られたアルゴリズムの実装がいくつかあります:

https://commons.apache.org/proper/commons- math / userguide / random.html

ただし、パフォーマンスには注意してください。 RandomDataGenerator のデフォルトコンストラクターは、 Well19937c の専用インスタンスを作成します。これは非常に高価な操作です。

ドキュメントによると、このクラスはスレッドセーフではありません が、1つのスレッドのみがこのクラスにアクセスすることを保証できる場合、スレッドごとに1つのインスタンスのみを初期化できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top