2
votes

I have some AES/GCM encrypted data and wanted to decrypt it. I want to decrypt it bypassing authentication as the data does not contain authentication information(Data is encrypted by a third party application). I tried decryption with javax.crypto package and it is always throwing tag mismatch error. Is there any way to bypass this tag checking and decrypt data. Data is encrypted with AES128 and it is using 12 byte initialization vector.

Edit: I got a temporary solution for this issue. Not sure if this is correct method.

            Key key = new SecretKeySpec(hlsKey, "AES");
            GCMParameterSpec gCMParameterSpec = new     GCMParameterSpec(96, initialisationVector);
            final Cipher c = Cipher.getInstance("AES/GCM/NoPadding", "BC");
            c.init(Cipher.DECRYPT_MODE, key, gCMParameterSpec);

            byte[] nodata = new byte[len * 2];
            System.arraycopy(cipherText, 0, nodata, 0, len);
            byte[] plaindata = new byte[len * 2];
            try { 

                int decrypted_index = 0;
                while (decrypted_index < len) {
                    int cp = c.update(nodata, decrypted_index, nodata.length - decrypted_index, plaindata, decrypted_index);//doFinal(nodata);
                    decrypted_index += cp;
                }
               if(decrypted_index>=len){
                   System.arraycopy(plaindata, 0, plainText, 0, len);
                   retvalue=1;
               }
            } catch (Exception e) {
                e.printStackTrace();
            }
1
The description doesn't make any sense. You say it was AES-GCM encrypted. OK, that means it has an authentication tag. A tag length of zero is not supported, the smallest length (for special cases only) is 32. Then you say it doesn't contain authentication information. Maybe it isn't encrypted with AES-GCM.President James K. Polk
@user1802492 Perhaps you mean there is no associated data not that it does not have authentication. There is no point in GCM mode without authentication..zaph
@JamesKPolk , I am getting this data from a third party application which encrypt data with AES/GCM and it is not providing authentication information, I want to decrypt this to know the actual data from device.Dijesh
I got a temporary solution for this issue, Not sure if this is correct methodDijesh
Please put the edit in an answer instead of in the question. The code is OK, but only if c.update does always return the plaintext data before validating the authentication tag. And that's implementation specific. It's also relatively inefficient wrt memory, but for a make-shift solution it is OK. Oh yeah, and the if(decrypted_index>=len){ test is of course bunk given the test within the while loop; decrypted_index must be >= len.Maarten Bodewes

1 Answers

8
votes

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.