web-dev-qa-db-ja.com

Javaで安全なランダムAESキーを作成する方法は?

標準のJDKを使用して、Javaで安全なランダムAESキーを生成する推奨方法は何ですか?

他の投稿でこれを見つけましたが、SecretKeyFactoryを使用することをお勧めします。

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom(); // cryptograph. secure random 
keyGen.init(random); 
SecretKey secretKey = keyGen.generateKey();

答えがランダムキーを生成する良い方法である理由の説明が含まれていれば素晴らしいでしょう。ありがとう!

50
barfuin

私はあなたの提案されたコードを使用しますが、少し単純化します:

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // for example
SecretKey secretKey = keyGen.generateKey();

プロバイダーがランダム性を取得する方法を選択できるようにします。プロバイダーが既に選択しているものほど良くないものを定義しないでください。

このコード例では、( Maartenが以下に指摘するようにJava.securityファイルを設定して、リストの先頭に優先プロバイダーを含めることを想定しています。プロバイダーを手動で指定する場合は、KeyGenerator.getInstance("AES", "providerName");を呼び出すだけです。

真に安全なキーを作成するには、キーを生成および保護するために ハードウェアセキュリティモジュール (HSM)を使用する必要があります。 HSMメーカーは通常、上記のコードを使用して、すべてのキー生成を行うJCEプロバイダーを提供します。

73
Duncan Jones

KeyGeneratorを使用することをお勧めします。 Duncanが示したように、初期化中にキーサイズを確実に指定します。 KeyFactoryは、既存のキーに使用するメソッドです。

OK、それでこれの核心に取り掛かることができます。原則として、AESキーには任意の値を設定できます。 (3)DESのような「弱いキー」はありません。 (3)DESパリティビットのように特定の意味を持つビットもありません。そのため、キーの生成は、ランダムな値を使用してバイト配列を生成し、その周りにSecretKeySpecを作成するのと同じくらい簡単です。

ただし、使用する方法にはまだ利点があります。KeyGeneratorは、キーを生成するために特別に作成されます。これは、コードがこの世代向けに最適化される可能性があることを意味します。このcouldには効率とセキュリティの利点があります。たとえば、キーを公開するタイミングサイドチャネル攻撃を回避するようにプログラムできます。キー情報がスワップファイルにリークされる可能性があるため、キー情報を保持しているbyte[]をクリアすることは既に良い考えであることに注意してください(とにかくこれはそうかもしれません)。

さらに、前述のように、すべてのアルゴリズムが完全にランダムなキーを使用しているわけではありません。したがって、KeyGeneratorを使用すると、他のアルゴリズムへの切り替えが容易になります。ただし、最新の暗号は完全にランダムなキーのみを受け入れます。これは、たとえばDES。

最後に、私の場合、最も重要な理由は、KeyGeneratorメソッドがセキュアトークン(スマートカード、TPM、USBトークンまたはHSM)内のAESキーを処理する唯一の有効な方法であるということです。 SecretKeySpecbyte[]を作成する場合、キーmustはメモリから取得されます。つまり、キーはセキュリティで保護されたトークンに入れられますが、キーは関係なくメモリに公開されます。通常、セキュアトークンは、セキュアトークンで生成されるか、またはたとえばスマートカードまたはキーセレモニー。キーがセキュアトークン内で直接生成されるように、KeyGeneratorをプロバイダーに提供できます。

Duncan's answer に示されているように、常にキーサイズ(およびその他のパラメーター)を明示的に指定します。これはwillであるため、プロバイダーのデフォルトに依存しないでください。アプリケーションの実行内容が不明確になり、各プロバイダーが独自のデフォルトを持つ場合があります。

23
Maarten Bodewes

他の投稿で多くの良いアドバイスをしています。これは私が使用するものです:

Key key;
SecureRandom Rand = new SecureRandom();
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256, Rand);
key = generator.generateKey();

別のランダムネスプロバイダーが必要な場合は、テスト用に使用しますが、Randを

MySecureRandom Rand = new MySecureRandom();
4
Andy