6

私は、暗号化を使用して何かを開発することに比較的慣れていません。現在、BouncyCastle と AES-GCM を使用して文字列を暗号化および復号化するクラスを作成しようとしています。暗号化を実装する際に考慮しなければならないことについて読みました。それらの 1 つは、常にランダム化された IV を使用する必要があるということでした。問題は、IV で Cipher を初期化しようとするたびに、テキストが適切に復号化されないことです。
次の例外がスローされるだけです。

javax.crypto.AEADBadTagException: mac check in GCM failed
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at BouncyCastleEX.decrypt(BouncyCastleEX.java:78)
at BouncyCastleEX.main(BouncyCastleEX.java:43)

次の方法を使用して、データを暗号化および復号化しています。

private static final String fallbackSalt = "ajefa6tc73t6raiw7tr63wi3r7citrawcirtcdg78o2vawri7t";
private static final int iterations = 2000;
private static final int keyLength = 256;
private static final SecureRandom random = new SecureRandom();

public byte[] encrypt(String plaintext, String passphrase, String salt)
        throws Exception {
    SecretKey key = generateKey(passphrase, salt);
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
    cipher.init(Cipher.ENCRYPT_MODE, key, generateIV(cipher),random);
    return cipher.doFinal(plaintext.getBytes());
}

public String decrypt(byte[] encrypted, String passphrase, String salt)
        throws Exception {
    SecretKey key = generateKey(passphrase, salt);
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
    cipher.init(Cipher.DECRYPT_MODE, key, generateIV(cipher),random);
    return new String(cipher.doFinal(encrypted));
}

private SecretKey generateKey(String passphrase, String salt)
        throws Exception {
    PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(),
            salt.getBytes(), iterations, keyLength);
    SecretKeyFactory keyFactory = SecretKeyFactory
            .getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
    return keyFactory.generateSecret(keySpec);
}

private IvParameterSpec generateIV(Cipher cipher) throws Exception {
    byte[] ivBytes = new byte[cipher.getBlockSize()];
    random.nextBytes(ivBytes);
    return new IvParameterSpec(ivBytes);
}

cipher.init(...) から「generateIV(cipher)」を削除すると、すべて問題なく動作します。しかし、私が知る限り、それは暗号化を非常に弱めます.

これがコードの小さな間違いなのか、それとも私が何も知らない何か他のものなのか、私にはわかりません。

本当にありがとうございました。

4

2 に答える 2

14

暗号化と復号化には同じ IV を使用する必要があります。秘密である必要はありませんが、AES-GCM に対してのみ一意です (技術的にはnonceです)。一般的な方法は、IV を暗号文の先頭に追加し、復号化の前に削除することです。

IV をランダムに生成する代わりに、メッセージ カウンターを使用することも一般的です。キーが変更された場合は、IV を初期値にリセットして、再度カウントを開始する必要があります。AES-GCM のセキュリティ保証が壊れるため、いくつかのメッセージで新しいキーが必要になります。その数は、2 48から 2 64メッセージの間のどこかです。

于 2016-02-22T16:49:19.543 に答える