IvParameterSpecの有無にかかわらず、AES暗号を初期化した場合、違いはありますか?
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
いくつかのサンプルテストデータでテストしましたが、暗号化と復号化の結果は同じです。
しかし、私はセキュリティの専門家ではないので、何も見逃したくないし、潜在的なセキュリティの抜け穴を作ります。私は疑問に思っていました、どちらが正しい方法ですか?
少し背景があります(すでにこれを知っている場合は申し訳ありませんが、同じ用語を使用していることを確認するだけの価値があります):
(ブロック暗号モードに関するウィキペディア http://en.wikipedia.org/wiki/Block_cipher_mode -は本当に優れており、IVが必要な理由を明確にしています。)
ブロックモードが異なれば、IV選択プロセスに異なる要件が課せられますが、それらすべてに共通することが1つあります。
同じIVとキーで2つの異なるメッセージを暗号化してはなりません。そうすると、攻撃者は通常、プレーンテキストを取得でき、場合によってはキー(または同等に有用なデータ)。
CBCは追加の制約を課します。つまり、IVは攻撃者にとって予測不可能でなければならないということです。したがって、artjom-bがSecureRandom
を使用して生成することを提案するのは良いことです。
さらに、artjob-bが指摘しているように、CBCはあなたに機密性を与えるだけです。それが実際に意味することは、あなたのデータが秘密に保たれているということですが、それが一体となって到着するという保証はありません。理想的には、GCM、CCM、EAXなどの認証済みモードを使用する必要があります。
これらのモードの1つを使用することは本当に、本当に良い考えです。 Encrypt-then-MACは、専門家にとっても扱いにくいものです。できれば避けてください。 (それを行う必要がある場合は、暗号化とMACに異なるキーを使用する必要があることを覚えておいてください。)
IvParameterSpecが指定されていない場合、Cipher shouldランダムIV自体を初期化しますが、あなたの場合はこれを行わないようです(new byte[16]
は0x00バイトで満たされた配列です)。 Cipherの実装が壊れているようです。その場合、常に新しいランダムIV(セマンティックセキュリティに必要)を提供する必要があります。
これは通常、次のように行われます。
SecureRandom r = new SecureRandom(); // should be the best PRNG
byte[] iv = new byte[16];
r.nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(iv));
次に暗号文を送信または保存するときは、その前にIVを追加する必要があります。復号化中は、暗号文の前面からIVをスライスして使用するだけで済みます。秘密にする必要はありませんが、一意である必要があります。
CBCモードだけでは機密性が得られることに注意してください。暗号文の任意のタイプの操作(悪意のあるまたは悪意のない)が可能な場合は、GCMやEAXなどの認証済みモードを使用する必要があります。それらはまたあなたに機密性に加えて完全性を与えるでしょう。それらにアクセスできない場合(SpongyCastleがそれらを持っている場合)、encrypt-then-MACスキームでメッセージ認証コード(MAC)を使用できますが、正しく実装するのははるかに困難です。