java - 与 IV 一起使用时,带有 BouncyCaSTLe 的 AES-GCM 抛出 "mac check in GCM failed"

标签 java encryption bouncycastle initialization-vector aes-gcm

我对开发加密产品还比较陌生。现在我正在尝试编写一个使用 BouncyCaSTLe 和 AES-GCM 加密和解密字符串的类。我了解了实现加密时必须考虑的事项。其中之一是您应该始终使用随机 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)”,一切都会完美无缺。但据我所知,它极大地削弱了加密。

正确知道我无法弄清楚这是代码中的一个小错误还是我一无所知的其他原因。

非常感谢您的帮助,非常感谢!

最佳答案

您必须使用相同的 IV 进行加密和解密。它不必是 secret 的,但对于 AES-GCM 来说只是唯一(从技术上讲,它是一个 nonce)。一种常见的方法是在密文前加上 IV,然后在解密前将其移除。

使用消息计数器而不是随机生成 IV 也很常见。如果更改了 key ,则应将 IV 重置为初始值并重新开始计数。在一定数量的消息中,您需要一个新 key ,因为 AES-GCM 的安全保证失效了。该数字介于 248 和 264 消息之间。

关于java - 与 IV 一起使用时,带有 BouncyCaSTLe 的 AES-GCM 抛出 "mac check in GCM failed",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35558249/

相关文章:

java - 对求偶数斐波那契数之和的运行时间感到困惑

java - OOP 继承,父级变量值未在子级上更新

java - 使用轻量级 API 生成 Bouncy CaSTLe RSA key 对

java - 使用 bouncycaSTLe 签名和验证签名的正确方法

java - OpenSSL 始终无法验证 Java 中 Bouncy CaSTLe 生成的签名

java - 看起来 "imperative"支持响应式(Reactive)代码的代码是否常见?

ssl - 当您在表格中输入数据时,它是加密的吗?

php - 在nodejs中使用初始向量进行aes-256-cbc加密解密

java - 基于 Java 代码的 Crypt::CBC 的 Perl 问题

java - Sparkr java错误