JavaでAESを使用してデータを暗号化し、Initialization Vectorで暗号を初期化したい。 256ビットのIVを使用できますか?または、128ビットIVのみを使用する必要がありますか?
IVは 動作モード に依存します。ほとんどのモード(CBCなど)では、IVはblockと同じ長さでなければなりません。 AESは128ビットブロックを使用するため、128ビットIVです。 AES-256は256ビットのキー(したがって名前)を使用しますが、128ビットのブロックを使用することに注意してください。
AESは、Rijndaelとして知られるブロック暗号のファミリのサブセットとして選択されました。そのファミリーには、3つの可能なブロックサイズ(128、192、および256ビット)と5つの可能なキーサイズ(128、160、192、224、および256ビット)の15以上のバリアントが含まれています。 [〜#〜] aes [〜#〜] は、NISTによって標準化された3つのバリアントのみを含み、すべてが128ビットブロックで、キーが128、192、または256ビットです。
さらに混乱させるために、一部のソフトウェアフレームワークはそれを誤解しました。例えばPHPは、「MCRYPT_RIJNDAEL_128」を使用して128ビットキーと128ビットブロックでRijndaelを指定します(つまり、AES-128と同じもの)。256ビットキーとRijndaelで「MCRYPT_RIJNDAEL_256」を使用し、 256ビットブロック(つまり、AESバリアントの1つではなく、特にAES-256ではまったくありません)。
128ビットのIVを使用する必要があります。 CBCモードの場合、IVはブロックサイズと一致する必要があります。ブロックサイズは、AESの場合は常に128ビットです。
AESの優勝候補であるRijndaelは、128および256ビットブロックに対して定義されていますが、AESとして標準化されたのは128ビットブロックのみです。一部のライブラリは256ビットブロックのRijndaelをサポートしますが、AESを使用しなくなります。
何らかの理由でより長いIVが必要な場合は、KDFまたはハッシュを使用して、元のキーとIVを実際にAESに使用するキーに変換できます。
Java=でのIVの処理は、使用される暗号化プロバイダーに依存します。Oracleランタイムに付属するSunプロバイダーはかなり厳格です。IVのブロックサイズと同じサイズである必要があります。ほとんどの 操作モード 。これは、ノンス(IVの最初のバイト)を指定する必要があると予想されたCTRモードでも当てはまります。もちろん、ECBモードはIVを必要としないため、IVを提供しようとすると例外がスローされます。
AESのブロックサイズは常に128ビットであるため、ほとんどの動作モードでは256ビットのIVは不可能です。いくつかの回答ですでに述べたように、Rijndaelは256ビットのブロックサイズで構成できますが、Rijndaelは標準ランタイムに含まれていません。 Rijndaelを使用するには、Bouncy Castleなどの追加のプロバイダーまたはライブラリが必要です。ブロック暗号AESはIVを入力として使用しないため、ECBモードにIVを提供できません。他のいくつかの言語/ランタイムはECBのIVを単に無視します
これで、256ビットIV(または実際にはnonce)を指定できる暗号が1つあり、それがGCMです。ただし、GCMは12バイトのノンスで最適に動作します。 GCMはデータ(ノンスを含む)を内部的にCTRモードの128ビットカウンターに変換します。
IVサイズを大きくしても、アルゴリズムの安全性が自動的に向上するわけではありません。 IVに256ビットの入力がある場合、入力にSHA-256ビットを使用し、代わりに左端の128ビットを使用できます。
Javaについて話していたので、ここにいくつかのコードがあります。IVサイズをいじって、"AES/CFB/NoPadding"
などのアルゴリズムを自分で試すことができます。 コードで使用されている静的IVはデモンストレーションのみを目的としています。 CTRには一意のIVが必要ですが、CBCにはランダムと攻撃者を区別できないIVが必要です。
SecretKey aesKey = new SecretKeySpec(new byte[256 / Byte.SIZE], "AES");
byte[] pt = "owlstead".getBytes(StandardCharsets.US_ASCII);
{
// === CBC mode requires an IV of the same size as the block size
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
// changing the IV size will result in an exception
byte[] ivBytes = new byte[c.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
{
// === CTR mode actually requires a complete IV in Java
// Java (or actually, the Sun provider) requires a 128 bit IV instead of just a nonce
Cipher c = Cipher.getInstance("AES/CTR/NoPadding");
// changing the IV size will result in an exception
byte[] ivBytes = new byte[c.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
{
// === GCM mode can do it!
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
byte[] ivBytes = new byte[256 / Byte.SIZE];
GCMParameterSpec gcmSpecWithIV = new GCMParameterSpec(128, ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpecWithIV);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
{
// === Java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
byte[] ivBytes = new byte[c.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivBytes);
c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] ct = c.doFinal(pt);
System.out.println(Hex.toHexString(ct));
}
IVの目的は、少し「混同」することです。
これがないと、平文の最初のブロックが同じメッセージはすべて、暗号文の最初のブロックが同じになります。このシナリオはそれほど珍しいことではありません。ファイルタイプに関する標準宣言で始まるファイル、またはSMTPがRCPT TO:、MAIL FROM:などを共通要素として使用する方法を検討してください。 128ビット(AESのブロックサイズ)は小さいので、このようなことが起こります。
操作にはさまざまなモードがありますが、CBCを最も単純な(そしておそらく最も一般的なものとして)使用して、あるブロックの暗号文が次のブロックにフィードされます。つまり、プレーンテキストの最初のブロックから作成された暗号化された出力(暗号文)が使用されますto XORブロック2の平文(その前に暗号化されます)。各ブロックの暗号文を使用してXOR(排他的OR)の平文次のブロック、したがって、Cipherブロック[〜#〜] chaining [〜#〜]という名前です。問題は、最初のブロックに先行するブロックがないことですそれ(とにかくCBCで...)
ここで最初に説明する問題が問題になります。同じテキストを使用して暗号化した場合、平文の最初のブロックが同じメッセージはすべて同じ暗号文の最初のブロックを共有します。
この問題を回避するために、IV(初期化ベクトル)が使用されます。これは、XOR(排他的OR)でチェーンを開始する最初のブロックに使用できる素材のブロックです。IVはメッセージと共に送信されます。それ以外の場合は、復号化を開始できません。
同じメッセージを同じキーで何度も再暗号化しても、最初の暗号化されたブロックは毎回異なるため、連鎖することにより、暗号化されたメッセージ全体が毎回異なります。
IVで何が行われているのかを考えた場合、私のCBCの例では、128ビットのブロックサイズより大きいまたは小さいサイズのIVについて説明しても意味がありません。これは、必要な最初のブロックのサイズだからです。 「混同」し、それ以降は、以前の暗号文を使用してチェーン化します。 (OKこれはすべてのモードに当てはまるわけではありません。一部のIVは最初のブロックよりも小さくする必要があるかもしれませんが、今のところCBCについて考えましょう)。したがって、CBCの場合、IVはブロックサイズと同じである必要があります。AESでは、(キーサイズに関係なく)常に128ビットです。
セキュリティのメリットは、IVの長さを考慮した場合ほどではありません。IVが長いほどセキュリティが向上する必要があるとは考えないでください。IVは重要ではありません。
IVの問題は、IVを生成する内容と方法の詳細です。それらは高品質である必要があります(つまり、以前に使用されたIVと統計的に関連のない均一な疑似ランダムマテリアル)。IV生成スキームまたはキースケジュールが不十分な場合、セキュリティを損なう可能性があり、統計に基づく暗号解析にそれを開く可能性があります。テクニック。
私が本当に述べたいのは、暗号化は少し複雑です:)であり、最善の意図的な間違いを犯したとしても、いくつかの破滅的な結果をもたらしました。それ以外の点では優れたスキームの一部は、小さな実装ミスによって完全に台無しになっています。ワイヤレスのWEPを覚えていますか?
関連するすべての要素を完全に深く理解していない場合は、標準に準拠し、よく使用されている(よく検討されている)ライブラリと確立されたプラクティスを使用してください。
すべての結果を理解しない限り、たとえ最善を尽くしても、何か賢いことをしようとすることは非常に危険です。私が非常に丁寧に言いたいのは、次のような質問をする必要がある場合は、使用するIVサイズは何ですか、実装方法を実験するのではなく、標準値に固執することです。
コーディングをお楽しみください...