web-dev-qa-db-ja.com

NativePRNGを使用したSecureRandomとSHA1PRNG

暗号的に強力な乱数とバイト配列を生成する必要があります。この目的のために、JavaのSecureRandomクラスを使用しています。しかし、暗号強度の観点から、どのPRNGアルゴリズムを選択するかわからない。

次のインスタンスのうち、より予測不可能な数値を生成するものはどれですか?またはそれらは等しいですか?

_SecureRandom nativePrng = SecureRandom.getInstance("NativePRNG")
SecureRandom sha1Prng = SecureRandom.getInstance("SHA1PRNG")
_

さらに、「Sun」プロバイダーを使用してこれらのインスタンスを生成できます(例:SecureRandom.getInstance("SHA1PRNG", "Sun"))。これは違いを生みますか?

前もって感謝します。

33
ovunccetin

TL; DR:不明な場合は new SecureRandom() を使用し、システムに認識させます。おそらく SecureRandom.getInstanceStrong() を長期キー生成に使用します。

乱数ジェネレーターがランタイムアプリケーション内で特定の出力シーケンスを生成することを期待しないでください。自分でシードした場合でも。


乱数ジェネレーターでは、どちらが最適かを常に判断するのは困難です。 LinuxとほとんどのUnixには非常によく考えられた乱数ジェネレーターがあるため、_/dev/random_または_/dev/urandom_を使用しても害はありません。つまり、 _"NativePRNG"_ です。 _/dev/random_の使用に関する問題は、十分なエントロピーが利用可能になるまでブロックすることです。したがって、キー生成に関して特別な要件がない限り、これに反対するアドバイスをします。


_"SHA1PRNG"_は、ハッシュ関数とカウンターをシードとともに使用します。アルゴリズムは比較的単純ですが、十分に説明されていません。一般的に安全であると考えられています。起動時にシステムジェネレータの1つからシードするだけなので、カーネルへの呼び出しが少なくて済むため、リソースの消費が少なくなる可能性が高い-私のシステムでは、_"NativePRNG"_( _/dev/urandom_)を使用します。どちらも、私のデュアルコアUbuntuノートパソコンの1つのコアのみに課税しているようです(一度に、あるコアから別のコアに頻繁に切り替わります。これはおそらく、カーネルスケジューリングのせいです)。高性能が必要な場合、特に_/dev/urandom_デバイスが特定のシステム構成で遅い場合、これを選択してください。

retiredApache Harmony実装に存在する_"SHA1PRNG"_は、Sunプロバイダのものとは異なることに注意してください(Oracleによって使用されます標準のJava SE実装)。Jakarta内のバージョンは、以前のバージョンのAndroidでも使用されていました。完全なレビュー、非常に安全ではないようです。

編集:そして、私はこれについて半分間違えていませんでした SHA1PRNGは、バージョン4.2.2未満の擬似ランダムではないことが示されています 以上 ここ

_"SHA1PRNG"_はnotであることに注意してくださいJava SE。ほとんどのランタイムでは存在します。 、ただしコードから直接参照すると、コードの移植性が低下します。


一般に、特定のプロバイダーを要求することもお勧めできません。プロバイダーを指定すると、相互運用性が損なわれる可能性があります。すべてのJavaランタイムがSunプロバイダーにアクセスできる場合があります-Androidは確かにそうではありません。また、実行時のアプリケーションの柔軟性が低下します。プロバイダーをリストの上位に配置して、代わりに使用することはできません。

そのため、提供する機能の1つに依存している場合にのみ、プロバイダーを示してください。たとえば、ランダムを生成する特定のハードウェアデバイス、またはFIPS認定済みの暗号化ライブラリがある場合は、プロバイダーを指定することをお勧めします。おそらくアルゴリズムを作成することをお勧めします/ providerプロバイダーを指定する必要がある場合は、アプリケーションの構成オプション。

プロバイダーを指定しないという考え方も、この Android開発者セキュリティブログ にあります。


したがって、特定のランダムジェネレータを選択しないようにしてください。代わりに、単純に空の引数コンストラクターに進みます: new SecureRandom() そして、システムに最適な乱数ジェネレーターを選択させます。新しい構成可能 SecureRandom.getInstanceStrong() in Java 8以降)を使用できます(長期キー生成などの特定の要件がある場合)。

SecureRandom のインスタンスをキャッシュしないでください。最初に自分自身に種をまかせて、VMで処理してください。顕著な違いは見られませんでした。操作。


SecureRandomをまったく使用しない場合:

一般的な警告として、乱数生成以外の目的で乱数ジェネレータを使用することは強くお勧めします。自分でシードできても、SunのSHA1PRNGを選択したとしても、乱数ジェネレーターから同じ乱数シーケンスを抽出できることを期待しないでくださいnotを使用して、1つの例を挙げると、パスワードからのキー派生に使用します。

繰り返しシーケンスが必要な場合は、ストリーム暗号を使用し、キーとIVのシード情報を使用します。ゼロで構成されるプレーンテキストを暗号化して、擬似乱数値のキーストリームを取得します。または、SHAKE128やSHAKE256(利用可能な場合)などの拡張出力関数(XOF)を使用することもできます。

利用可能なRNGのパフォーマンスが不十分で、セキュリティが問題にならない場合は、SecureRandomの代わりに別の安全でない乱数ジェネレーターを検討することをお勧めします。 SecureRandom実装は、メルセンヌツイスターアルゴリズムや Random クラスによって実装されるアルゴリズムなどの非セキュアな乱数ジェネレーターほど高速ではありません。これらは、セキュリティや品質よりも単純さと速度のために最適化されています。

SecureRandom classを拡張して、決定論的なシードされたランダムな実装をライブラリ呼び出しに挿入することができます。このようにして、ライブラリは、明確に定義された出力を持つ疑似乱数ジェネレーターを取得します。ただし、乱数ジェネレータはアルゴリズムによってさまざまな方法で使用できることに注意してください。例えば。 RSAは、最適化された素数を見つける最適化された方法に切り替えることができ、DES鍵は、調整または直接計算されたパリティビットで生成されます。

52
Maarten Bodewes

参照から ここ

ネイティブPRNG Solaris/Linuxの実装。/dev/randomおよび/ dev/urandomと対話するため、これらのファイルが存在する場合にのみ使用可能です。それ以外の場合、SHA1PRNGがこのクラスの代わりに使用されます。

Sunプロバイダーがデフォルトとして使用される場合があります(主に存在するプロバイダーの順序に依存します)。

4
nitishagar