我对Java AES GCM加密有问题。我已经按照this page上的说明生成了以下代码:
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 (...)
答案 0 :(得分:2)
我终于找到了自己的错误。错误是在解密方法中,我尝试对整个接收到的消息而不是仅对提取的密文进行doFinal (...)
。我在问题中留下了错误,并在此处张贴了程序的相关部分(现已正确)。 @kelalaka谢谢您的努力。
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