是的,可以解密不带有身份验证标签的消息:如果您阅读了GCM规范,则可以看到CTR的IV只是IV,后面加上四个字节
00000002(即,计数器从零开始,为计算而增加了一个)身份验证标签,然后再次输入加密计数器的起始值)。
所以这是代码,
inc我用它两次来验证我的计数器代码。当然也可以简单地将最后一个字节设置为value
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)。如果标签完全缺失
- TAG_SIZE /Byte.SIZE,
doFinal请将其删除。
编辑2:请注意,这假定12字节/ 96位IV,这是GCM的默认IV大小。对于其他尺寸,您需要首先计算IV。



