Yes, it is possible to decrypt the message without the authentication tag: if you read the GCM specification you can see that the IV for CTR is simply the IV, appended with four bytes 00000002
(i.e. a counter starting at zero, increased by one for calculating the authentication tag and again for the starting value of the counter for encryption).
So here's the code, where I do the inc
twice as I used it to validate my counter code; it is of course possible to simply set the last byte to value 0x02
as well.
package nl.owlstead.so;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.util.Arrays;
public class DecryptGCMWithoutVerification {
private static final int TAG_SIZE = 128;
public DecryptGCMWithoutVerification() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) throws Exception {
// --- encryption using GCM
Cipher gcm = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey key = new SecretKeySpec(new byte[16], "AES");
byte[] ivBytes = new byte[12];
GCMParameterSpec iv = new GCMParameterSpec(TAG_SIZE, ivBytes);
gcm.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] ct = gcm.doFinal("owlstead".getBytes(StandardCharsets.US_ASCII));
// --- decryption using underlying CTR mode
Cipher ctr = Cipher.getInstance("AES/CTR/NoPadding");
// WARNING: this is only correct for a 12 byte IV in GCM mode
byte[] counter = Arrays.concatenate(ivBytes, new byte[4]);
inc(counter);
inc(counter);
IvParameterSpec ctrIV = new IvParameterSpec(counter);
ctr.init(Cipher.DECRYPT_MODE, key, ctrIV);
byte[] pt = ctr.doFinal(ct, 0, ct.length - TAG_SIZE / Byte.SIZE);
System.out.println(new String(pt, StandardCharsets.US_ASCII));
}
private static final byte inc(byte[] counter) {
for (int i = counter.length - 1; i >= 0; i--) {
if (++counter[i] != 0) {
return 0;
}
}
return 1;
}
}
EDIT: this code is for an invalid tag or a tag that cannot be recalculated (the AAD could be missing, for instance). Remove - TAG_SIZE / Byte.SIZE
from doFinal
if the tag is missing entirely.
EDIT 2: note that this assumes a 12 byte / 96 bit IV, the default IV size for GCM. For any other size you need to calculate the IV first.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…