Javaで暗号的に強力な乱数が必要な場合は、を使用しますSecureRandom
。残念ながら、SecureRandom
非常に遅くなる可能性があります。/dev/random
Linux で使用する場合、十分なエントロピーが増加するのを待つことをブロックできます。パフォーマンスの低下をどのように回避しますか?
誰かがこの問題の解決策としてアンコモン数学を使用しましたか?
このパフォーマンスの問題がJDK 6で解決されたことを誰かが確認できますか?
Javaで暗号的に強力な乱数が必要な場合は、を使用しますSecureRandom
。残念ながら、SecureRandom
非常に遅くなる可能性があります。/dev/random
Linux で使用する場合、十分なエントロピーが増加するのを待つことをブロックできます。パフォーマンスの低下をどのように回避しますか?
誰かがこの問題の解決策としてアンコモン数学を使用しましたか?
このパフォーマンスの問題がJDK 6で解決されたことを誰かが確認できますか?
回答:
真のランダムデータが必要な場合は、残念ながらそれを待つ必要があります。これには、SecureRandom
PRNG のシードが含まれます。Uncommon MathsはSecureRandom
、インターネットに接続して特定のWebサイトからシードデータをダウンロードすることはできますが、真のランダムデータをより速く収集することはできません。私の推測では、これが/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
(余分に注意してください/./
)
/dev/urandom
、Sunはこれを魔法の文字列として扱い、/dev/random
とにかく使用するため、偽装する必要があります。ときにあるfile:
URLではないfile:
URLは?Sunがそうではないと判断した場合はいつでも:-(
file:/dev/urandom
in -Djava.security.egd
またはinを使用securerandom.source
して/dev/random/
も、いつでもSecureRandom.getSeed()
(またはsetSeed()
呼び出されても)読み取られるようです。file:/dev/./urandom
結果がまったく読み取ら/dev/random
れないという回避策(straceで確認)
/dev/urandom/
は、それを使用して新しいハードウェアですぐにシークレットを生成した場合に何が起こるかだと思います。/dev/urandom/
エントロピーをブロックすべきではありません。デバイスの初回起動時に最初に行うことが公開鍵と秘密鍵のペアの生成である場合など、シークレットが永続的である場合、状況はさらに悪化します。これらの恐ろしい状況以外では、とにかく/dev/urandom
一般的なSecureRandom
アルゴリズムを使用するよりも良い方法です。
Linuxでは、のデフォルトの実装SecureRandom
はNativePRNG
(ソースコードはここ)で、非常に遅くなる傾向があります。Windowsでは、デフォルトはです。SHA1PRNG
他の人が指摘したように、明示的に指定すればLinuxでも使用できます。
NativePRNG
SHA1PRNG
Uncommons MathsのAESCounterRNGとは異なり、オペレーティングシステムからエントロピーを継続的に受信します(から読み取ります/dev/urandom
)。他のPRNGは、シード後に追加のエントロピーを取得しません。
AESCounterRNGはの約10倍高速でSHA1PRNG
、IIRC自体はの2倍または3倍高速ですNativePRNG
。
初期化後にエントロピーを取得するより高速なPRNGが必要な場合は、Fortunaの Java実装を見つけることができるかどうかを確認してください。Fortuna実装のコアPRNGはAESCounterRNGで使用されるものと同じですが、エントロピープーリングと自動再シードの高度なシステムもあります。
多くのLinuxディストリビューション(主にDebianベース)は/dev/random
、エントロピーに使用するようにOpenJDKを構成しています。
/dev/random
本質的に遅いです(そしてブロックすることさえできます)。
ここから、ブロックを解除する方法について2つのオプションがあります。
オプション1、エントロピーを改善する
よりエントロピーを得るに/dev/random
は、hagedgedデーモンを試してください。これは、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
代わりに切り替えることができます。これにより、ブロックされないことが保証されます。
これをグローバルに行うにjre/lib/security/java.security
は、デフォルトのJavaインストールのファイルを編集して使用します/dev/urandom
(別のバグのため、として指定する必要があります/dev/./urandom
)。
このような:
#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom
その後、コマンドラインで指定する必要はありません。
注:暗号化を行う場合は、適切なエントロピーが必要です。ポイントのケース- アンドロイドPRNGの問題は、ビットコインの財布のセキュリティを低下させました。
/dev/random
的に遅い(そしてブロックすることさえできる)」は間違っている。それは完全にシステム構成に依存します。新しいマシンが使用できるCPUで例えばA速いRNGを有していてもよく、およびBSDマシンは、一般的に同じ実装を持っている/dev/random
と/devl/urandom
。それでも、必ずしも高速であることに依存 するべきではありません/dev/random
。VM上では、クライアントOSのRNGを使用できるように、クライアントVMにクライアントツールセットをインストールすることができます。
本当に「暗号的に強力な」ランダム性が必要な場合は、強力なエントロピーソースが必要です。/dev/random
システムイベントがエントロピー(ディスクの読み取り、ネットワークパケット、マウスの動き、キーの押下など)を収集するまで待機する必要があるため、処理が遅くなります。
より高速なソリューションは、ハードウェア乱数ジェネレーターです。あなたはすでにあなたのマザーボードに1つを内蔵しているかもしれません。hw_randomのドキュメントを調べて、持っているかどうかを確認する方法とその使用方法を確認してください。rng-toolsパッケージには、ハードウェアで生成されたエントロピーをにフィードするデーモンが含まれています/dev/random
。
システムでHRNGを使用できず、パフォーマンスのためにエントロピー強度を犠牲にしてもかまわない場合は、からのデータを使用して適切なPRNGをシードし/dev/random
、PRNGが作業の大部分を実行するようにします。SP800-90にリストされているNIST承認のPRNG には、実装が簡単なものがいくつかあります 。
Java 8を使用して、Linuxの呼び出しでアルゴリズムSecureRandom.getInstanceStrong()
が得られることを発見しましたNativePRNGBlocking
。これは、数バイトのソルトを生成するために、数秒間ブロックすることがよくあります。
NativePRNGNonBlocking
代わりに明示的に要求するように切り替えましたが、名前から予想されるように、ブロックされなくなりました。これがセキュリティにどのような影響を与えるかはわかりません。おそらく非ブロッキングバージョンでは、使用されるエントロピーの量を保証できません。
簡単に言うと、ブロックを回避するには、を使用しますnew SecureRandom()
。これは/dev/urandom
、ブロックせず、基本的にと同じくらい安全なを使用し/dev/random
ます。投稿から:「/ dev / randomを呼び出したいのは、マシンが最初に起動するときだけで、エントロピーはまだ蓄積されていません」。
SecureRandom.getInstanceStrong()
絶対的に最強のRNGを提供しますが、大量のブロッキングが影響しない状況でのみ安全に使用できます。
getInstanceStrong()
します。それでもnew SecureRandom()
、FIPS準拠のキーペアジェネレーターまたは乱数ジェネレーターを使用したいと思います。つまり、ブロックしない場合 、これは答えを提供します。/dev/urandom
結局のところ、結局のところそれは結局のところ、やはりシステムエントロピーに依存しています。しかし、それは一般的に非常に良いアドバイスです。場合/dev/urandom
ブロックあなたは問題ではなく、Javaアプリケーションのソースを修正する必要があります。
システムに人為的なランダム性を与えるツール(少なくともUbuntuでは)があります。コマンドは単純です:
rngd -r /dev/urandom
前面にsudoが必要な場合があります。rng-toolsパッケージがない場合は、インストールする必要があります。私はこれを試しました、そしてそれは間違いなく私を助けました!
ソース:マットvsワールド
sudo rngd -r /dev/urandom
がsudo apt install rng-tools
ありました
私は同じ問題に直面しました。適切な検索語句でグーグル検索した後、DigitalOceanに関するこの素晴らしい記事を見つけました。
私はここの記事から関連する部分を引用しているだけです。
HAVEGEの原則に基づいており、以前はその関連ライブラリに基づいていたhasgedは、プロセッサでのコード実行時間の変化に基づいてランダム性を生成できます。同じハードウェアの同じ環境でも、1つのコードが同じ時間で実行されるのはほぼ不可能であるため、単一または複数のプログラムを実行するタイミングは、ランダムソースをシードするのに適しています。hasged実装は、ループを繰り返し実行した後、プロセッサーのタイムスタンプカウンター(TSC)の違いを使用して、システムのランダムソース(通常は/ dev / random)をシードします。
この記事の手順に従ってください。https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged
あなたが参照した問題/dev/random
は、SecureRandom
アルゴリズムではなく、アルゴリズムが使用するランダム性のソースにあります。2つは直交しています。2つのうちどちらがあなたを遅くしているのかを理解する必要があります。
あなたが明示的にリンクした珍しい数学のページは、それらがランダム性の原因を扱っていないことを述べています。
BouncyCastleなどのさまざまなJCEプロバイダーを試して、の実装SecureRandom
が速いかどうかを確認できます。
簡単な検索では、デフォルトの実装をFortunaに置き換えるLinuxパッチも明らかになります。これについてはあまり詳しくありませんが、調査を歓迎します。
また、不適切に実装されたSecureRandom
アルゴリズムやランダムソースを使用することは非常に危険ですが、独自のJCEプロバイダーをのカスタム実装でロールすることもできますSecureRandomSpi
。プロバイダーに署名させるには、Sunとのプロセスを経る必要がありますが、実際には非常に簡単です。暗号化ライブラリに対する米国の輸出制限を知っていることを記載したフォームをFAXで送信する必要があるだけです。
安全なランダムを再帰アルゴリズムの初期化ソースとして使用します。UncommonMathでの作業の代わりにMersenneツイスターを使用してバルク作業を行うことができます。
http://en.wikipedia.org/wiki/Mersenne_twister
初期化に使用される安全なランダムをリフレッシュしてください。たとえば、クライアントごとに1つのメルセンヌツイスター擬似ランダムジェネレーターを使用して、クライアントごとに1つの安全なランダムを生成し、十分な高度のランダム化を取得できます。
Random
が、には適していませんSecureRandom
。
ドキュメントによると、 SecureRandomで使用されるさまざまなアルゴリズムは、優先順に次のとおりです。
Linuxについて質問したので、Windowsの実装と、Solarisでのみ実際に利用できるSunPKCS11を無視します。ただし、自分でインストールした場合を除き、これを尋ねることはありません。
それらの同じドキュメントによると、これらのアルゴリズムが使用するものは
SHA1PRNG
初期シードは、現在システム属性とjava.securityエントロピー収集デバイスの組み合わせを介して行われます。
NativePRNGが
nextBytes()
使用/dev/urandom
generateSeed()
するもの/dev/random
NativePRNGBlocking
nextBytes()
とgenerateSeed()
使用/dev/random
NativePRNGNonBlocking
nextBytes()
とgenerateSeed()
使用/dev/urandom
つまり、を使用する場合SecureRandom random = new SecureRandom()
、機能するリスト(通常はNativePRNG)が見つかるまでそのリストを検索します。そして、それはそれ自体からシードする/dev/random
(または明示的にシードを生成する場合はそれを使用する)ことを意味し/dev/urandom
、次のバイト、int、double、booleans、what-have-yousを取得するために使用します。
ので/dev/random
(それはエントロピープールに十分なエントロピーを有するまでブロック)をブロックして、その性能を阻害することができます。
その解決策の1つは、十分なエントロピーを生成するために老朽化したもののようなものを使用する/dev/urandom
ことです。別の解決策は、代わりに使用しています。jvm全体に設定することもできますがSecureRandom
、を使用して、のこの特定のインスタンスに設定することをお勧めしますSecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking")
。NativePRNGNonBlockingの場合、このメソッドはNoSuchAlgorithmExceptionをスローする可能性があるため、デフォルトにフォールバックする準備をしてください。
SecureRandom random;
try {
random = SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException nsae) {
random = new SecureRandom();
}
また、他の* nixシステムで/dev/urandom
は動作が異なる場合があることに注意してください。
/dev/urandom
ランダムに十分な?従来の知恵は、/dev/random
十分にランダムなだけであるということを持っています。ただし、一部の声は異なります。で「使用するSecureRandomための正しい方法」と「は/ dev / urandomの程度神話」は、その主張されて/dev/urandom/
ちょうど良いようです。
情報セキュリティスタック上のユーザーはこれに同意します。基本的に、質問する必要がある場合/dev/urandom
は、目的に応じて問題ありません。
私自身はこの問題に直面していませんが、プログラムの開始時にすぐにスレッドを生成し、すぐにシードを生成しようとしてから死にます。ランダムに呼び出すメソッドは、スレッドが生きている場合はそのスレッドに参加するため、最初の呼び出しは、プログラム実行の非常に早い段階で発生した場合にのみブロックされます。
私の経験は、PRNGの初期化が遅いだけで、その後のランダムデータの生成ではありません。より熱心な初期化戦略を試してください。それらは作成にコストがかかるため、シングルトンのように扱い、同じインスタンスを再利用します。1つのインスタンスに対してスレッドの競合が多すぎる場合は、それらをプールするか、スレッドローカルにします。
乱数生成について妥協しないでください。弱点があると、セキュリティがすべて損なわれます。
COTSの原子崩壊ベースのジェネレータはあまり見かけませんが、ランダムデータが本当に必要な場合のために、いくつかの計画があります。HotBitsを含め、常に注目すべきものが1つあるサイトは、John WalkerのFourmilabです。
SecureRandom
は、エントロピー収集において過去10年間に数回変更されたと思います。
SecureRandom
がまだ問題である可能性は低いですが、システムの低いエントロピーが常に問題になります。シングルトンを使用すると、強結合コードが作成されます。これは、設計のアンチパターンです。したがって、細心の注意を払って使用する必要があります。問題を修正する場合は、コード内のすべての参照を逆にする必要があります。
RNG要件について明確にする必要があるようです。(私が理解しているように)最も強力な暗号化RNG要件は、それらを生成するために使用されるアルゴリズムを知っていて、以前に生成されたすべての乱数を知っていても、非現実的な量の計算能力を費やすことなく、将来。
このランダム性の完全な保証が必要ない場合は、おそらく適切なパフォーマンスのトレードオフがあります。Uncommons-MathsまたはFortunaからのAESCounterRNGに関するDan Dyerの応答に同意する傾向があります(その著者の1人は暗号化の専門家であるBruce Schneierです)。私もどちらも使用したことがありませんが、一見するとそのアイデアは評判が良いようです。
私は考えだと思いますが、定期的に初期乱数の種を生成することができればということ(例えば一日一回または時間または何ごと)、あなたがストリーム暗号は、ちょうどそのXORを使用している場合(ストリームの連続した塊から乱数を生成するために、高速ストリーム暗号を使用することができますnullのストリームを渡すか、XORビットを直接取得します)。ECRYPTのeStreamプロジェクトには、パフォーマンスベンチマークを含む多くの優れた情報があります。これは、補充する時点の間のエントロピーを維持しません。そのため、誰かが乱数と使用したアルゴリズムのいずれかを知っている場合、技術的には、大量の計算能力で、ストリーム暗号を解き、将来の乱数を予測できるように、その内部状態を推測します。しかし、そのリスクとその結果がエントロピーを維持するコストを正当化するのに十分であるかどうかを判断する必要があります。
編集:これは、ネットで見つけたRNGの暗号化コースノートで、このトピックに非常に関連しているようです。
ハードウェアがサポートしている場合は、私が作成者であるJava RdRandユーティリティを使用してみてください。
これはIntelのRDRAND
指示に基づいておりSecureRandom
、大容量の実装の場合よりも約10倍高速で、帯域幅の問題はありません。
この実装は、命令を提供するCPUでのみ機能することに注意してください(つまり、rdrand
プロセッサフラグが設定されている場合)。RdRandRandom()
コンストラクタを介して明示的にインスタンス化する必要があります。特定のものProvider
は実装されていません。
RDRAND
は良い情報源だと思いますが、それは少し信頼できません。それは間違いなく、コレクターへの多数の入力の1つである必要があります(David Johnstonに害はありません)。