java - AES GCM解密绕过JAVA中的身份验证

标签 java encryption aes-gcm

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

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

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

最佳答案

警告:危险 Material 。仅当您了解在不首先验证身份验证标记的情况下处理生成的明文的含义时,才继续。这不仅会导致攻击者更改消息,还会通过明文 oracle 攻击危及 secret 性。


是的,可以在没有身份验证标记的情况下解密消息:如果您阅读 GCM 规范,您可以看到 CTR 的 IV 就是简单的 IV,附加四个字节 00000002(即一个从零开始的计数器,增加 1 以计算身份验证标记,并再次增加计数器的起始值以进行加密)。

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

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

编辑 2:请注意,这假定一个 12 字节/96 位 IV,这是 GCM 的默认 IV 大小。对于任何其他尺寸,您需要先计算 IV。

关于java - AES GCM解密绕过JAVA中的身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49228671/

相关文章:

java - 是否有用于 buildScript 依赖项的 Gradle "dependencies "任务?

java - 如何知道一个文件代表的是根目录还是我的电脑?

android - 混淆android Assets 文件

encryption - 为什么我无法使用 WireShark 查看其他设备上的流量

ubuntu - PJSIP 构建找不到 OpenSSL AES GCM 支持

java - 如何从 AES-GCM 密文中去除签名?

java - 我如何加密和解密在 PHP 和 JAVA 之间使用 AES/GCM/

java - Android水平滚动

java - 如何将 java (Android) 加密参数转换为 iOS 加密?

java - Paypal Android SDK 错误 "request failed with server response:shutdown" "SERVER_COMMUNICATION_ERROR"