当前位置: 首页 > 知识库问答 >
问题:

带有BouncyCastle的AES-GCM在与IV一起使用时抛出“GCM中的MAC检查失败

尉迟彬
2023-03-14

我对用加密技术开发东西比较陌生。现在,我正在尝试编写一个类,它使用带有AES-GCM的BouncyCastle加密和解密字符串。我读过关于实现加密时必须考虑的事情。其中之一是你应该经常使用随机静脉注射。问题是,每次我尝试用IV初始化密码时,它不会正确解密我的文本。
它只是抛出以下异常:

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)”一切工作都完美无缺。但据我所知,它极大地削弱了加密。

是的,我不知道这是代码中的一个小错误,还是其他什么我不知道的东西。

共有1个答案

邴奇逸
2023-03-14

您必须使用相同的IV进行加密和解密。它不一定是秘密的,但只对AES-GCM是唯一的(它在技术上是一个偶然的)。一种常见的方法是在密文前预置IV并在解密前将其删除。

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

 类似资料:
  • 我目前正在将我的C#AES-GCM密码代码转换为PHP。然而,经过一些研究,我的PHP系统加密的文本不能被C#one解密。我想知道这两种代码是否有区别: C#带弹跳壳: 下面是PHP系统: 有没有人能告诉我,PHP代码中是否有遗漏或不同之处,导致它们的工作方式有所不同?或者PHP函数和BouncyCastle函数之间是否存在某种内部差异,从而使它们有所不同?

  • tag到底是什么意思?我们为什么需要它?

  • 在首次尝试实现AES-GCM的过程中,面临着身份验证标记生成、加密密码生成和GCM mac校验失败的问题。对于当前实现,正在填充,但仍然为空。因此,给出了“”。这似乎是围绕字节数组大小的一些问题,能否有人分享一下,应该在什么基础上确定输出缓冲区大小?这是不是应该分块进行? 任何指向AES-GCM实施的指针/链接都将受到高度赞赏。 以下是我们的实施情况: 它给出以下例外情况: 提前谢谢!!

  • 我正在尝试使用AES/EAX/Nopadding执行加密/解密。由于EAX似乎没有BouncyCastle可用,所以BC被添加为提供程序。 null 我有一个AES/GCM/nopadding的实现,它使用了同样的代码,工作得很好。 我做错了什么?

  • 编辑:问题可以简化为:下面的Node.js代码给出了一个“无效的IV长度”错误。为什么?静脉注射应该是什么? 我在GCM模式下使用AES来加密一些数据,但我使用两种不同的语言和库来加密和解密,它们似乎对我需要的东西有不同的词汇表。 我正在使用Python库(Crypto)进行加密。方法接受128位密钥和消息,并返回128位nonce、128位标记和密文。 (加密代码取自本例) 我用默认的node.