Java AES GCM标记不匹配

Java AES GCM标记不匹配,java,encryption,aes,aes-gcm,Java,Encryption,Aes,Aes Gcm,我对Java AES GCM加密有问题。我已按照上的说明生成以下代码: package aes; import java.nio.ByteBuffer; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AES { pr

我对Java AES GCM加密有问题。我已按照上的说明生成以下代码:

package aes;

import java.nio.ByteBuffer;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AES {
    private Cipher encryptCipher;
    private Cipher decryptCipher;
    private byte[] key;
    private int keyLength;
    private SecretKeySpec keySpec;
    private SecureRandom random;

    public AES(String key) {
        try {
            this.key = key.getBytes();
            this.keyLength = this.key.length*8; // key length in bits
            this.keySpec = new SecretKeySpec(this.key, "AES");
            this.encryptCipher = Cipher.getInstance("AES/GCM/NoPadding");
            this.decryptCipher = Cipher.getInstance("AES/GCM/NoPadding");
            this.random = SecureRandom.getInstance("SHA1PRNG");
        }
        catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }
    public byte[] encrypt(byte[] plaintext) {
        try {
            byte[] iv = new byte[12]; // create new IV
            random.nextBytes(iv); 
            encryptCipher.init(Cipher.ENCRYPT_MODE, keySpec, new GCMParameterSpec(keyLength, iv));
            byte[] encrypted = encryptCipher.doFinal(plaintext);
            ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + encrypted.length);
            byteBuffer.put(iv);
            byteBuffer.put(encrypted);
            return byteBuffer.array(); // IV(0)...IV(11) + ENCRYPTED(0)...ENCRYPTED(N)
        }
        catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
            return null;
        }
    }
    public byte[] decrypt(byte[] ciphertext) {
        try {
            ByteBuffer byteBuffer = ByteBuffer.wrap(ciphertext);
            byte[] iv = new byte[12];
            byteBuffer.get(iv);
            byte[] encrypted = new byte[byteBuffer.remaining()];
            byteBuffer.get(encrypted);
            decryptCipher.init(Cipher.DECRYPT_MODE, keySpec, new GCMParameterSpec(keyLength, iv));
            return decryptCipher.doFinal(ciphertext);
        }
        catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
            return null;
        }
    } 
}
大体上,我把整个事情称为:

package aes;

public class Main {
    static byte[] plaintext = new byte[] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53};
    public static void main(String[] args) {
        AES aes = new AES("Random09Random09");

        byte[] encrypted = aes.encrypt(plaintext);
        byte[] decrypted = aes.decrypt(encrypted);  
    }
}
现在我总是会遇到这样的标记不匹配错误:

Tag mismatch!
javax.crypto.AEADBadTagException: Tag mismatch!
    at com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:578)
    at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1049)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:985)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at aes.AES.decrypt(AES.java:55)
    at aes.Main.main(Main.java:9)
我无法确定原因。StackTrace对我没有帮助。如果有人能帮我,我将不胜感激。正如您在StackTrace中看到的,错误在步骤中的解密中

doFinal (...)

我终于自己发现了错误。错误是,在解密方法中,我试图做最后的。。。就整体而言,接收到的信息并不仅仅是提取的密文。我在问题中留下了错误,并在这里发布了程序的相关部分@凯拉拉卡:谢谢你的努力

    public byte[] decrypt(byte[] ciphertext) {
        try {
            ByteBuffer byteBuffer = ByteBuffer.wrap(ciphertext);
            byte[] iv = new byte[12];
            byteBuffer.get(iv);
            byte[] encrypted = new byte[byteBuffer.remaining()];
            byteBuffer.get(encrypted);
            decryptCipher.init(Cipher.DECRYPT_MODE, keySpec, new GCMParameterSpec(keyLength, iv));
            return decryptCipher.doFinal(encrypted); // here was the mistake
        }
        catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
            return null;
        }
    } 
主要问题是:

package aes;

public class Main {
    static byte[] plaintext = new byte[] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53};
    public static void main(String[] args) {
        AES aes = new AES("Random09Random09");

        byte[] encrypted = aes.encrypt(plaintext);
        byte[] decrypted = aes.decrypt(encrypted);  
        System.out.println("Original:\n" + new String(plaintext) + "\nEncrypted:\n" + new String(encrypted) + "\nDecrypted:\n" + new String(decrypted));
    }
}
现在程序的正确输出是:

Original:
ABCDEFGHIJKLMNOPQRS
Encrypted:
�~q꽕kl�9���&�ZB=�WPU�"�'�H���]:?Bo
Decrypted:
ABCDEFGHIJKLMNOPQRS

我终于自己发现了错误。错误是,在解密方法中,我试图做最后的。。。就整体而言,接收到的信息并不仅仅是提取的密文。我在问题中留下了错误,并在这里发布了程序的相关部分@凯拉拉卡:谢谢你的努力

    public byte[] decrypt(byte[] ciphertext) {
        try {
            ByteBuffer byteBuffer = ByteBuffer.wrap(ciphertext);
            byte[] iv = new byte[12];
            byteBuffer.get(iv);
            byte[] encrypted = new byte[byteBuffer.remaining()];
            byteBuffer.get(encrypted);
            decryptCipher.init(Cipher.DECRYPT_MODE, keySpec, new GCMParameterSpec(keyLength, iv));
            return decryptCipher.doFinal(encrypted); // here was the mistake
        }
        catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
            return null;
        }
    } 
主要问题是:

package aes;

public class Main {
    static byte[] plaintext = new byte[] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53};
    public static void main(String[] args) {
        AES aes = new AES("Random09Random09");

        byte[] encrypted = aes.encrypt(plaintext);
        byte[] decrypted = aes.decrypt(encrypted);  
        System.out.println("Original:\n" + new String(plaintext) + "\nEncrypted:\n" + new String(encrypted) + "\nDecrypted:\n" + new String(decrypted));
    }
}
现在程序的正确输出是:

Original:
ABCDEFGHIJKLMNOPQRS
Encrypted:
�~q꽕kl�9���&�ZB=�WPU�"�'�H���]:?Bo
Decrypted:
ABCDEFGHIJKLMNOPQRS

@凯拉拉卡,这是一个解决方案吗?据我所知,Base64只是一种获取可打印字符的编码。这与标签问题有什么关系?正如问题中提到的,我从一个网站上获得了代码的基本部分。在那里,整个过程似乎都在起作用。我不明白为什么MEAH不是这样,GCM模式需要标签。cipher.updateaadad;这在加密中丢失。见第48行。结果是一样的吗?@kelalaka感谢你的努力和你发布的链接。不是这样。尽管如此,我还是发现了错误。我将很快创建一个答案。无关:您可能希望确保this.key=key.getBytes;适合你的需要。StringgetBytes是一种依赖于系统的方法,它依赖于主机系统的默认编码方案,在linux上通常为UTF8,但在Windows、其他*nix、MacOS上为YMMV,或者如果您使用特殊环境变量或-Dfile启动JVM。编码。。。您可能想检查您的密码来自俄语、汉语还是拉丁字母?考虑到整个系统的外部程序,字符串如何转换为字节。@kelalaka这是一个解决方案吗?据我所知,Base64只是一种获取可打印字符的编码。这与标签问题有什么关系?正如问题中提到的,我从一个网站上获得了代码的基本部分。在那里,整个过程似乎都在起作用。我不明白为什么MEAH不是这样,GCM模式需要标签。cipher.updateaadad;这在加密中丢失。见第48行。结果是一样的吗?@kelalaka感谢你的努力和你发布的链接。不是这样。尽管如此,我还是发现了错误。我将很快创建一个答案。无关:您可能希望确保this.key=key.getBytes;适合你的需要。StringgetBytes是一种依赖于系统的方法,它依赖于主机系统的默认编码方案,在linux上通常为UTF8,但在Windows、其他*nix、MacOS上为YMMV,或者如果您使用特殊环境变量或-Dfile启动JVM。编码。。。您可能想检查您的密码来自俄语、汉语还是拉丁字母?以及如何将字符串转换为字节,通过将系统作为一个整体考虑到外部程序。除了SHA1PRNG和密钥生成之外,看起来还不错。另外,SecretKey和SecretKeySpec在使用后应该被清除…@SaptarshiBasu这个问题是指我的另一个问题,可以在这里看到。我现在要尝试AES/GCM,可能必须使用SHA1PRNG,尽管这对于我的应用程序来说仍然非常缓慢。Java程序最终将在Beagle Bone板上运行。CPU资源有限,我仍然希望找到一种比SHA1PRNG更快的方法。看起来比SHA1PRNG和密钥生成更好。另外,SecretKey和SecretKeySpec在使用后应该被清除…@SaptarshiBasu这个问题是指我的另一个问题,可以在这里看到。我现在要尝试AES/GCM,可能必须使用SHA1PRNG,尽管这对于我的应用程序来说仍然非常缓慢。Java程序最终将在Beagle Bone板上运行。CPU资源有限,我仍然希望找到一种比SHA1PRNG更快的方法。