AES GCM 解密绕过 JAVA 中的身份验证 [英] AES GCM decryption bypassing authentication in JAVA

查看:29
本文介绍了AES GCM 解密绕过 JAVA 中的身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些 AES/GCM 加密数据,想解密它.我想绕过身份验证解密它,因为数据不包含身份验证信息(数据由第三方应用程序加密).我尝试用 javax.crypto 包解密,它总是抛出标签不匹配错误.有没有办法绕过这个标签检查和解密数据.数据采用AES128加密,使用12字节初始化向量.

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.

我得到了这个问题的临时解决方案.不确定这是否是正确的方法.

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();
            }

推荐答案

是的,可以在没有身份验证标签的情况下解密消息:如果您阅读 GCM 规范,您会发现 CTR 的 IV 只是 IV,附加四个字节00000002(即从零开始的计数器,增加一用于计算认证标签,再次增加用于加密的计数器的起始值).

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).

这里是代码,我用它来验证我的计数器代码时执行了两次 inc;当然也可以简单地将最后一个字节设置为值 0x02.

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;
    }

}

此代码用于无效标签或无法重新计算的标签(例如,AAD 可能丢失).如果标签完全丢失,则从 doFinal 中删除 - TAG_SIZE/Byte.SIZE.

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:请注意,这里假设 12 字节/96 位 IV,即 GCM 的默认 IV 大小.对于任何其他尺寸,您需要先计算 IV.

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.

这篇关于AES GCM 解密绕过 JAVA 中的身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆