java AES-GCM:AEADBadTagException:GCM 中的 mac 检查失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27402716/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 11:45:20  来源:igfitidea点击:

AES-GCM: AEADBadTagException: mac check in GCM failed

javaaes-gcm

提问by user36009

While trying to implement AES-GCM for the first time, we are facing issue in generating AuthenticationTag, Encrypted cipher & GCM mac check fails in the end. For out current implementation tag[]is being populated but byte[] encryptedremains empty. And because of this cipher.doFinal(data1, offset)gives 'mac check in GCM failed'. It appears to be some issue around the size of byte arrays, can someone please share on what basis should the output buffer size be determined? Should this be done in chunks?

第一次尝试实现 AES-GCM 时,我们在生成 AuthenticationTag 时遇到了问题,加密密码和 GCM mac 检查最终失败。对于当前的实现tag[]正在填充但byte[] encrypted仍然为空。正因为如此,cipher.doFinal(data1, offset)给出了 ' mac check in GCM failed'。字节数组的大小似乎存在一些问题,有人可以分享应该根据什么确定输出缓冲区大小吗?这应该分块完成吗?

Any pointers/links to AES-GCM implementation will be highly appreciated.

任何指向 AES-GCM 实现的指针/链接都将受到高度赞赏。

Following is our implementation:

以下是我们的实现:

public class GCMTest {

    public static void main(String[] args) throws Exception {

        //***********************************************************
        //Key
        byte[] key = MessageDigest.getInstance("MD5").digest("1234567890123456".getBytes("UTF-8"));//this is the random key

        //Iv
        SecureRandom srand = SecureRandom.getInstance("SHA1PRNG");
        byte[] iv = new byte[256];
        srand.nextBytes(iv);

        //Input
        byte[] data="inputPlainText".getBytes();

        final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);

        //***********************************************************
        //Encryption
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", new BouncyCastleProvider());
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), gcmParameterSpec);

        cipher.updateAAD("MyAAD".getBytes("UTF-8"));

        //Encrypted output
        final byte[] encrypted = new byte[cipher.getOutputSize(data.length)];
        cipher.update(data, 0, data.length, encrypted, 0);  //Not being updated for current data. 

        //Tag output
        byte[] tag = new byte[cipher.getOutputSize(data.length)];
        cipher.doFinal(tag, 0);


        //***********************************************************
        //Decryption
        final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

        cipher.updateAAD("MyAAD".getBytes("UTF-8"));

        //What size should be assigned to outputBuffer?
        final byte[] data1 = new byte[256];

        int offset = cipher.update(encrypted, 0, encrypted.length, data1, 0);
        cipher.update(tag, 0, tag.length, data1, offset);
        cipher.doFinal(data1, offset);

        boolean isValid = checkEquals(data, data1);
        System.out.println("isValid :"+isValid);
    }

    private static boolean checkEquals(byte[] a, byte[] b)
    {
        int diff = a.length ^ b.length;
        for(int i = 0; i < a.length && i < b.length; i++)
            diff |= a[i] ^ b[i];
        return diff == 0;
    }
}

It gives following exception:

它给出了以下异常:

Exception in thread "main" 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:408)
    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:2068)
    at GCMTest.main(GCMTest.java:56)

Thanks in advance!!

提前致谢!!

回答by Dakota Jay Whipple

I was having this same issue. For me, it had to do with encoding the string. I ended up doing:

我遇到了同样的问题。对我来说,它与编码字符串有关。我最终做了:

  1. Get ASCII bytes from string you want to encrypt (UTF-8 in your case)
  2. Encrypt bytes
  3. Encode bytes in Base64 string
  1. 从要加密的字符串中获取 ASCII 字节(在您的情况下为 UTF-8)
  2. 加密字节
  3. 在 Base64 字符串中编码字节

Then to decrypt string I did:

然后解密字符串我做了:

  1. Decode encrypted string to Base64 bytes
  2. Decrypt Base64 bytes
  3. Create new string using ASCII.
  1. 将加密字符串解码为 Base64 字节
  2. 解密 Base64 字节
  3. 使用 ASCII 创建新字符串。

Here is the code :

这是代码:

private String encrypt(String src) {
    byte[] srcBytes = src.getBytes(StandardCharsets.US_ASCII);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, secureRandom);

    byte[] cipherText = cipher.doFinal(srcBytes);
    byte[] encryptedBytes = new byte[12 + cipherText.length];

    System.arraycopy(ivBytes, 0, encryptedBytes, 0, 12);
    System.arraycopy(cipherText, 0, encryptedBytes, 12, cipherText.length);

    return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
}

private String decrypt(String encryptedString) {
    byte[] encryptedBytes = Base64.decode(encryptedString, Base64.DEFAULT);

    cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, encryptedBytes, 0, 12));
    byte[] decryptedBytes = cipher.doFinal(encryptedBytes, 12, encryptedBytes.length-12);

    return Base64.encodeToString(decryptedBytes, Base64.DEFAULT);
}

Any variables I didn't include how to initialize them can be inferred from the java docs. I was trying to do this in Android so I'm not sure how different it is. I found this post to be incredibly helpful: Java AES/GCM/NoPadding - What is cipher.getIV() giving me?

我没有包括如何初始化它们的任何变量都可以从 java 文档中推断出来。我试图在 Android 中做到这一点,所以我不确定它有多大不同。我发现这篇文章非常有用:Java AES/GCM/NoPadding - What is cipher.getIV() give me?

回答by go to

you should update section code

你应该更新部分代码

error section code:

错误部分代码:

//What size should be assigned to outputBuffer?
final byte[] data1 = new byte[256];

int offset = cipher.update(encrypted, 0, encrypted.length, data1, 0);
cipher.update(tag, 0, tag.length, data1, offset);
cipher.doFinal(data1, offset);

update the new code:

更新新代码:

final byte[] data1 = new byte[encrypted.length];
int offset = cipher.update(encrypted, 0, encrypted.length, data1, 0);
offset += cipher.update(tag, 0, tag.length, data1, offset);
cipher.doFinal(data1, offset);