【问题标题】:AES/GCM/NoPadding AEADBadTagExceptionAES/GCM/NoPadding AEADBadTagException
【发布时间】:2018-02-19 13:27:55
【问题描述】:

我正在尝试使用 AES/GCM/NoPadding 在 Java8 中进行加密。但我无法弄清楚为什么我在解密时会出现 AEADBadTagException。

这是我的代码:

private final int GCM_IV_LENGTH = 12;
private final int GCM_TAG_LENGTH = 16;

private static String encrypt(String privateString, SecretKey skey) {
    byte[] iv = new byte[GCM_IV_LENGTH];
    (new SecureRandom()).nextBytes(iv);

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
    cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);

    byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));
    byte[] encrypted = new byte[iv.length + ciphertext.length];
    System.arraycopy(iv, 0, encrypted, 0, iv.length);
    System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);

    Base64Encoder encoder = new Base64Encoder();
    String encoded = encoder.encode(encrypted);

    return encoded;
}

private static String decrypt(String encrypted, SecretKey skey) {
    Base64Decoder decoder = new Base64Decoder();
    String decoded = encoder.encode(encrypted);

    byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
    cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);

    byte[] ciphertext = cipher.doFinal(decoded, GCM_IV_LENGTH, decoded.length - GCM_IV_LENGTH);

    String newString = new String(ciphertext, "UTF8");

    return newString;
}

希望有人能帮我解决这个异常。谢谢!

【问题讨论】:

  • 这是java吗?您的方法声称返回字符串,但实际上尝试返回 byte[]。请发布编译代码。 How to create a MCVE
  • 我的错。我对其进行了编辑并添加了缺失的代码。是的,这是 java。
  • 您的代码无法编译。自己试试。 byte[] iv = new Byte[GCM_IV_LENGTH]; 不正确。
  • 你去。很抱歉错字错误,我无法复制代码,因为它在另一台电脑上,所以我只是重写了它。请多多包涵。
  • 啊,好吧,这听起来很痛苦。好吧,在我修复了剩余的错别字等之后,它运行良好,对我来说没有例外。

标签: java encryption aes-gcm


【解决方案1】:

我已经纠正了一些错别字,并使用了 Java 8 的 base64 实用程序,它对我来说似乎工作得很好。这是我的版本,你可以和你的比较一下。

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

public class Main {
    private final static int GCM_IV_LENGTH = 12;
    private final static int GCM_TAG_LENGTH = 16;

    private static String encrypt(String privateString, SecretKey skey) throws Exception {
        byte[] iv = new byte[GCM_IV_LENGTH];
        (new SecureRandom()).nextBytes(iv);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
        cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);

        byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));
        byte[] encrypted = new byte[iv.length + ciphertext.length];
        System.arraycopy(iv, 0, encrypted, 0, iv.length);
        System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);

        String encoded = Base64.getEncoder().encodeToString(encrypted);

        return encoded;
    }

    private static String decrypt(String encrypted, SecretKey skey) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(encrypted);

        byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
        cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);

        byte[] ciphertext = cipher.doFinal(decoded, GCM_IV_LENGTH, decoded.length - GCM_IV_LENGTH);

        String result = new String(ciphertext, "UTF8");

        return result;
    }

    public static void main(String[] args) throws Exception {
        SecretKey key = new SecretKeySpec(new byte[16], "AES"); // key is 16 zero bytes
        String s = decrypt(encrypt("This is the first string to test", key), key);
        System.out.println(s);
    }
}

【讨论】:

  • 哦,我现在明白了。我尝试使用 java.util.Base64 并发现我错过了将我的 eclipse 配置为 java 8。我真的相信它已经在 java 8 中运行了。多么愚蠢的大声笑。非常感谢!
  • getDecoder 仅适用于 Android API 26。我们如何处理旧平台?
  • @IgorGanapolsky:使用android.util.Base64
  • 如果您在此处加密时提供GCMParameterSpec cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);,则会在异常中得到Caller-provided IV not permitted 作为原因。
猜你喜欢
  • 1970-01-01
  • 2021-09-24
  • 2016-11-14
  • 2018-09-20
  • 2021-11-23
  • 2021-12-05
  • 2019-05-30
  • 2018-02-11
  • 1970-01-01
相关资源
最近更新 更多