Java 8で_AES/GCM/NoPadding
_暗号化を使用していますが、コードにセキュリティ上の欠陥があるかどうか疑問に思っています。私のコードはwork、テキストを暗号化および復号化しますが、いくつかの詳細は不明です。
私の主な質問はこれです:
_Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????
_
IVは、「特定のキーについて、IVを繰り返してはならない」という要件を満たしますか。 from RFC 4106 ?
また、関連する質問(以下を参照)についての回答や洞察をいただければ幸いですが、その最初の質問が私を最も悩ませています。これに答えるソースコードやドキュメントの場所を知りません。
以下に、大まかな完全なコードを示します。この投稿を書いているときにエラーを導入した場合は謝罪します:
_class Encryptor {
Key key;
Encryptor(byte[] key) {
if (key.length != 32) throw new IllegalArgumentException();
this.key = new SecretKeySpec(key, "AES");
}
// the output is sent to users
byte[] encrypt(byte[] src) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // See question #1
assert iv.length == 12; // See question #2
byte[] cipherText = cipher.doFinal(src);
assert cipherText.length == src.length + 16; // See question #3
byte[] message = new byte[12 + src.length + 16]; // See question #4
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(cipherText, 0, message, 12, cipherText.length);
return message;
}
// the input comes from users
byte[] decrypt(byte[] message) throws Exception {
if (message.length < 12 + 16) throw new IllegalArgumentException();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, key, params);
return cipher.doFinal(message, 12, message.length - 12);
}
}
_
ユーザーが私の秘密鍵を破る=ゲームオーバーだとします。
より詳細な質問/関連する質問:
Cipher.getIV()によって返されるIVは、この方法で使用しても安全ですか?
cipher.getIV()
を避けて、自分のカウンターで自分でIVを構築する必要がありますか?cipher.getIV()
を実装するソースコードはどこかでオンラインで利用できますか?そのIVは常に12バイト長ですか?
認証タグは常に16バイト(128ビット)の長さですか?
#2と#3、およびパディングの欠如により、暗号化されたメッセージは常に_12 + src.length + 16
_バイト長になりますか? (そして、私はそれらを1バイト配列に安全に押しつぶすことができます、それに対して正しい長さを知っていますか?
ユーザーが知っている一定のsrcデータがある場合、無制限の数のsrcデータ暗号化をユーザーに表示しても安全ですか?
Srcデータが毎回異なる場合(たとえば、System.currentTimeMillis()
または乱数を含む)、無制限の数のsrcデータ暗号化をユーザーに表示しても安全ですか?
暗号化する前にsrcデータに乱数をパディングすると役立つでしょうか?前後にランダムな8バイト、または一方の端だけで言うと?または、それはまったく役に立ちません/私の暗号化を悪化させますか?
(これらの質問はすべて自分のコードの同じブロックに関するものであり、互いに強く関連しており、同じ機能を実装するときに他の人が同じ質問のセットを持っている必要があるため、質問を複数に分割するのは間違っていると感じましたStackOverflowの形式により適している場合は、個別に再投稿できます。教えてください!)
Q1:cipher.getIV()によって返されるIVは、この方法で使用しても安全ですか?
はい、少なくともOracleが提供する実装用です。デフォルトのSecureRandom
実装を使用して個別に生成されます。サイズは12バイト(GCMのデフォルト)なので、96ビットのランダム性があります。カウンターが繰り返される可能性は非常に小さいです。 Oracle JDKのベースとなるOpenJDK(GPL化)でソースを検索できます。
ただし、他のプロバイダーの動作が異なる可能性があるため、独自のランダムな12バイトを生成することをお勧めします。
Q2:そのIVは常に12バイト長ですか?
GCMのデフォルトである可能性が非常に高いですが、他の長さareはGCMに有効です。ただし、アルゴリズムは、12バイト以外のサイズについて追加の計算を行う必要があります。弱点があるため、12バイト/ 96ビットとAPIを維持することを強くお勧めします[IVサイズの選択を制限する場合があります。
Q3:認証タグは常に16バイト(128ビット)の長さですか?
いいえ、64ビットから128ビットの範囲で8ビット単位でバイト単位でサイズを指定できます。小さい場合は、認証タグの左端のバイトのみで構成されます。 GCMParameterSpec
呼び出しの3番目のパラメーターとして init
を使用して、別のサイズのタグを指定できます。
GCMの強度はタグのサイズに強く依存することに注意してください。 128ビットに保つことをお勧めします。大量の暗号化テキストを生成する場合は、96ビットが最小である必要があります特に.
Q4:#2と#3で、パディングがないため、暗号化されたメッセージは常に12 + src.length + 16バイトの長さになりますか? (そして、私はそれらを1バイト配列に安全に押しつぶすことができ、そのために正しい長さを知っていますか?)
上記を参照。 Oracleプロバイダーの場合がこれに該当します。 GCMParameterSpec
を使用して確認してください。
Q5:ユーザーが知っている一定のsrcデータがある場合、無制限の数のsrcデータ暗号化をユーザーに表示しても安全ですか?
事実上非バインド、はい。約2 ^ 48の暗号化の後、私は心配し始めます。ただし、一般的にはdesign forキーの変更が必要です。
Q6:srcデータが毎回異なる場合(たとえば、System.currentTimeMillis()または乱数を含む)、無制限の数のsrcデータ暗号化をユーザーに表示しても安全ですか?
Q5の回答をご覧ください
Q7:暗号化の前に乱数でsrcデータをパディングすると役立ちますか?前後にランダムな8バイト、または一方の端だけで言うと?または、それはまったく役に立ちません/私の暗号化を悪化させますか?
いいえ、まったく役に立ちません。 GCMはCTRモードを使用するため、キーストリームで暗号化されます。 not IVとして機能します。事実上無限の数の暗号文(2 ^ 48!以上)が必要な場合は、その乱数とキーをキー派生関数またはKDFに使用することをお勧めします。 HKDFは現在最高の品種ですが、Bouncy Castleを使用するか、自分で実装する必要がある場合があります。