我AES/GCM/NoPadding
在java中使用加密(我对它很陌生)。如果我理解正确,GCM 应该识别加密的消息是否被操纵,如果是,它不应该解密它。如this anwser所述:
身份验证 TAG 是解密的输入,如果有人篡改了您的关联数据或您的加密数据,GCM 解密会注意到这一点并且不会输出任何数据(或返回错误,您应该丢弃接收到的数据而不对其进行处理)
但是,在我的代码中,如果我修改加密消息(消息部分或标签部分),我不会收到任何错误并且消息将被解密(当然会有所不同)。即使我提供不同的密钥,我也没有收到任何错误,尽管消息会被错误地解密......
我究竟做错了什么?请看下面的代码:
实用程序类:
public class CryptoUtils {
public static byte[] encrypt(byte[] key, byte[] iv, byte[] input) throws GeneralSecurityException {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
int outputLength = cipher.getOutputSize(input.length);
byte[] output = new byte[outputLength];
int outputOffset = cipher.update(input, 0, input.length, output, 0);
cipher.doFinal(output, outputOffset);
return output;
} catch (NoSuchAlgorithmException e) {
Timber.wtf(e);
}
return null;
}
public static byte[] decrypt(byte[] key, byte[] iv, byte[] encrypted) throws GeneralSecurityException {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
return cipher.doFinal(encrypted);
} catch (NoSuchAlgorithmException e) {
Timber.wtf(e);
}
return null;
}
}
不引发错误的代码:
byte[] key = getKey();
byte[] iv = generateIv();
byte[] message = "hello".getBytes();
byte[] encrypted = CryptoUtils.encrypt(key, iv, message);
//Split decrypted message into parts.
byte[] encryptedMessage = new byte[message.length];
System.arraycopy(encrypted, 0, encryptedMessage, 0, message.length);
byte[] tag = new byte[encrypted.length - message.length];
System.arraycopy(encrypted, message.length, tag, 0, tag.length);
//I am modifying the message here.
encryptedMessage[0] = 0;
// I am also modifying the key.
key[2] = 0;
//Put message and tag together.
byte[] toDecrypt = new byte[encrypted.length];
System.arraycopy(encryptedMessage, 0, toDecrypt, 0, encryptedMessage.length);
System.arraycopy(tag, 0, toDecrypt, encryptedMessage.length, tag.length);
//Still not getting any errors here.
byte[] decrypted = CryptoUtils.decrypt(key, iv, encryptedMessage);
byte[] decryptedMessage = new byte[message.length];
System.arraycopy(decrypted, 0, decryptedMessage, 0, message.length);
//Decrypted message is different than original.
Timber.d("Decrypted message: %s", new String(decryptedMessage));