[解決済み] 与えられた最終ブロックが適切にパディングされていない
質問
パスワードベースの暗号化アルゴリズムを実装しようとしているのですが、この例外が発生します。
javax.crypto.BadPaddingException: 与えられた最終ブロックが適切にパディングされていません
何が問題なのでしょうか?
以下は私のコードです。
public class PasswordCrypter {
private Key key;
public PasswordCrypter(String password) {
try{
KeyGenerator generator;
generator = KeyGenerator.getInstance("DES");
SecureRandom sec = new SecureRandom(password.getBytes());
generator.init(sec);
key = generator.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] encrypt(byte[] array) throws CrypterException {
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(array);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] decrypt(byte[] array) throws CrypterException{
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(array);
} catch(Exception e ){
e.printStackTrace();
}
return null;
}
}
(JUnitのテスト)
public class PasswordCrypterTest {
private static final byte[] MESSAGE = "Alpacas are awesome!".getBytes();
private PasswordCrypter[] passwordCrypters;
private byte[][] encryptedMessages;
@Before
public void setUp() {
passwordCrypters = new PasswordCrypter[] {
new PasswordCrypter("passwd"),
new PasswordCrypter("passwd"),
new PasswordCrypter("otherPasswd")
};
encryptedMessages = new byte[passwordCrypters.length][];
for (int i = 0; i < passwordCrypters.length; i++) {
encryptedMessages[i] = passwordCrypters[i].encrypt(MESSAGE);
}
}
@Test
public void testEncrypt() {
for (byte[] encryptedMessage : encryptedMessages) {
assertFalse(Arrays.equals(MESSAGE, encryptedMessage));
}
assertFalse(Arrays.equals(encryptedMessages[0], encryptedMessages[2]));
assertFalse(Arrays.equals(encryptedMessages[1], encryptedMessages[2]));
}
@Test
public void testDecrypt() {
for (int i = 0; i < passwordCrypters.length; i++) {
assertArrayEquals(MESSAGE, passwordCrypters[i].decrypt(encryptedMessages[i]));
}
assertArrayEquals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[1]));
assertArrayEquals(MESSAGE, passwordCrypters[1].decrypt(encryptedMessages[0]));
try {
assertFalse(Arrays.equals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[2])));
} catch (CrypterException e) {
// Anything goes as long as the above statement is not true.
}
try {
assertFalse(Arrays.equals(MESSAGE, passwordCrypters[2].decrypt(encryptedMessages[1])));
} catch (CrypterException e) {
// Anything goes as long as the above statement is not true.
}
}
}
解決方法は?
PKCS5 でパディングされたデータを間違った鍵で復号し、パディングを解除すると (Cipher クラスが自動的に行います)、ほとんどの場合 BadPaddingException (255/256 より少し少ない、約 99.61%) が発生します。パディングは特殊な構造を持っており、解除時に検証されるため、有効なパディングを生成する鍵は非常に少なくなるからです。
ですから、もしこの例外が発生したら、それをキャッチして "間違ったキー" として扱ってください。
また、間違ったパスワードを入力し、そのパスワードを使って鍵ストアから鍵を取得したり、鍵生成機能を使って鍵に変換した場合にも発生する可能性があります。
もちろん、輸送中にデータが破損した場合にも、不正なパディングが発生する可能性があります。
とはいえ、あなたのスキームにはセキュリティ上の注意点があります。
-
パスワードベースの暗号化では、SecureRandomとKeyGeneratorを使うのではなく、SecretKeyFactoryとPBEKeySpecを使うべきでしょう。理由は、SecureRandomはJavaの実装ごとに異なるアルゴリズムになる可能性があり、異なるキーを与えるからです。SecretKeyFactoryは、定義された方法で鍵の導出を行います(正しいアルゴリズムを選択すれば、安全であるとみなされる方法です)。
-
ECB-modeは使わないでください。これは各ブロックを独立して暗号化するため、同一の平文ブロックは常に同一の暗号文ブロックになることを意味します。
好ましくは、安全な 動作モード CBC (Cipher block chaining) や CTR (Counter) のような。あるいは、GCM (Galois-Counter mode) や CCM (Counter with CBC-MAC) のような、認証も含むモードを使用することもできます。
-
通常、機密性だけでなく、メッセージが改ざんされていないことを確認するための認証も必要です。(これは暗号に対する選択暗号文攻撃も防ぐことができ、つまり機密保持に役立ちます)。そこで、メッセージにMAC(メッセージ認証コード)を追加するか、認証を含む暗号モードを使用します(前項参照)。
-
DESの有効な鍵のサイズはわずか56ビットです。この鍵空間は非常に小さく、熱心な攻撃者であれば数時間でブルートフォースさせることができます。もし、パスワードで鍵を生成した場合は、さらに速くなります。 また、DESはブロックサイズが64ビットしかないため、連鎖的なモードではさらに弱点が増えます。 代わりに、AESのような最新のアルゴリズムを使用してください。 128ビット(標準型)。
関連
-
[解決済み】不正なエスケープ文字"㊧"について
-
[解決済み】デフォルトのキーストアファイルが存在しない?
-
[解決済み】Javaで文字列をコピーするにはどうしたらいいですか?
-
[解決済み】Eclipseで「JUnitテストが見つかりませんでした。
-
[解決済み] java.sql.SQLException を取得しました。ResultSet が終了した後の操作は許可されません。
-
[解決済み】Eclipseで「パッケージエクスプローラー」ビューが見つからない
-
[解決済み] 複数の例外を1行でキャッチする(ブロックを除く)
-
[解決済み] すべての例外をキャッチする `try`/`except` ブロックはどのように書けばよいですか?
-
[解決済み] 例外を正しく無視する方法
-
[解決済み】Javaではfinallyブロックは必ず実行されるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Android Studio クラス org.codehaus.groovy.runtime.InvokerHelper を初期化できませんでした。
-
[解決済み] hibernateでResultSetを抽出できない。
-
[解決済み】"|="の意味は何ですか?(パイプ等号演算子)
-
[解決済み】「error: '.class' expected」の意味と修正方法について
-
[解決済み】-XX:MaxPermSizeは何をするのですか?
-
[解決済み】Javaでユーザー入力を待機させる方法
-
[解決済み] JavaでSSLピアが正しくシャットダウンされない
-
[解決済み】Javaの未処理例外について
-
[解決済み】Javaの".class expected "について
-
[解決済み】CreateProcess error=2, The system cannot find file specified.