2

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();
            }
Dijesh
  • 334
  • 2
  • 11
  • 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 Mar 12 '18 at 16:17
  • @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 Mar 12 '18 at 23:30
  • @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 Mar 15 '18 at 12:47
  • I got a temporary solution for this issue, Not sure if this is correct method – Dijesh Mar 15 '18 at 12:52
  • 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 Aug 24 '18 at 07:45

1 Answers1

10

Warning: hazardous material. Only proceed if you understand the implications of handling the resulting plaintext without verifying the authentication tag first. This could lead not just to an attacker changing the message, but also compromising confidentiality through plaintext oracle attacks.


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.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • You're in luck because your IV is 12 bytes. Needs additional work for other length IV's. – rustyx Oct 30 '18 at 12:01
  • 2
    `GCMBlockCipher` from Bouncy Castle gives an example how to calculate CTR IV for all lengths of IV. Enough to implement similar to what they do with J0 in init(). Then you need to increment it and you can use `SICBlockCipher` to decrypt passing J0 as IV. – Roman Nikitchenko Oct 30 '18 at 12:14
  • 1
    Note to readers: In case it's not obvious, this is the crypto equivalent of replacing a fuse with a bent nail. Sure, it may "work", but you've just bypassed a major safety feature with a dodgy hack and it's 100% your fault if your house burns down or your cryptosystem gets compromised. – Ilmari Karonen Aug 25 '21 at 17:13
  • I have had a similar issue here: https://stackoverflow.com/questions/71651996/javascript-decrypt-for-aes-gcm-not-working-but-in-python-it-works when porting a small python script to JavaScript, where I just could not find out, why I could not decrypt. After adding authTag = iv + "00000002", now it works like a charm. Still not fully understanding, why, and why the python library (cryptodome) is doing this "transparently"? Thanks for the hint! – fritz Mar 29 '22 at 11:19
  • @fritz In hindsight this may be AES-GCM-SIV (synthetic IV) but I would need to verify that. – Maarten Bodewes Nov 24 '22 at 23:20