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

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

问题描述

我有一些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.

编辑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.

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

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