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
AES-GCM: AEADBadTagException: mac check in GCM failed
提问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[] encrypted
remains 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:
我遇到了同样的问题。对我来说,它与编码字符串有关。我最终做了:
- Get ASCII bytes from string you want to encrypt (UTF-8 in your case)
- Encrypt bytes
- Encode bytes in Base64 string
- 从要加密的字符串中获取 ASCII 字节(在您的情况下为 UTF-8)
- 加密字节
- 在 Base64 字符串中编码字节
Then to decrypt string I did:
然后解密字符串我做了:
- Decode encrypted string to Base64 bytes
- Decrypt Base64 bytes
- Create new string using ASCII.
- 将加密字符串解码为 Base64 字节
- 解密 Base64 字节
- 使用 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);