简体   繁体   English

双重加密/解密失败,但单一加密/解密失败-AES 256位

[英]Double encryption / decryption fails but single does not - AES 256 bit

So this particular exception is pretty common, yet my problem is slightly different from what is usually asked. 因此,这种特殊情况非常普遍,但是我的问题与通常提出的问题略有不同。

I've got a AES decrytpion and encryption function defined as followed: 我已经定义了AES解密和加密功能,如下所示:

    public static byte[] encrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
            throws java.io.UnsupportedEncodingException,
            NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException,
            IllegalBlockSizeException,
            BadPaddingException {

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher;
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
        return cipher.doFinal(textBytes);
    }

    public static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
            throws java.io.UnsupportedEncodingException,
            NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            InvalidAlgorithmParameterException,
            IllegalBlockSizeException,
            BadPaddingException {

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return cipher.doFinal(textBytes);
    }

Now if I perform a single decryption like this: 现在,如果我像这样执行一次解密:

System.out.println(Arrays.toString(
                AES256Cipher.decrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
                        AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
                                AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(bKeys[b]), HexBytePlainWriter.hexStringToByteArray(zkeys[a^b]))
                                )
                        )));

The byte array outputs just fine. 字节数组输出就可以了。 Whereas if I perform double encryption/decryption: 而如果我执行双重加密/解密:

        System.out.println("dec: " + HexBytePlainWriter.ByteToHexString(
            AES256Cipher.decrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
                    AES256Cipher.decrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(bKeys[b]),
                            AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(aKeys[a]),
                                    AES256Cipher.encrypt(ivBytes, HexBytePlainWriter.hexStringToByteArray(bKeys[b]), HexBytePlainWriter.hexStringToByteArray(zkeys[a^b]))
                                    )
                            ))));

I get the famous javax.crypto.BadPaddingException: Given final block not properly padded Exception. 我得到了著名的javax.crypto.BadPaddingException: Given final block not properly padded Exception。 Note that a and b are just integers (assume they are both 0). 请注意, ab只是整数(假设它们都为0)。 Currently, the IVBytes is just an empty byte array of size 16, declared with new byte[16] . 当前,IVBytes只是一个大小为16的空字节数组,用new byte[16] and aKeys and bKeys are both String arrays with AES encypted (random) strings (length 32 bytes). aKeysbKeys都是带有AES加密(随机)字符串(长度为32个字节)的String数组。

These are the helper functions I use (to turn byte[] into a hex string and vice versa): 这些是我使用的辅助函数(将byte []转换为十六进制字符串,反之亦然):

public static  String ByteToHexString (byte[] data) {
        StringBuilder buf = new StringBuilder();
        for (byte b : data) {
            int halfbyte = (b >>> 4) & 0x0F;
            int two_halfs = 0;
            do {
                buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
                halfbyte = b & 0x0F;
            } while (two_halfs++ < 1);
        }
        return buf.toString();
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

I suspect that the output of the first decryption malforms the ciphertext in such a way that the outer part throw the exception. 我怀疑第一次解密的​​输出会使密文格式错误,以至于外部会引发异常。 I've check the size and the outer part outputs 32 bytes, so that should be OK. 我检查了大小,外部部分输出了32个字节,因此应该可以。 Does this not comply with the PKC5Padding? 这不符合PKC5Padding吗?

Any help is much appreciated. 任何帮助深表感谢。

Edit: 编辑:

It looks like my minimal example was faulty: I used key B first instead of A. Jon Skeet did give me an idea though. 看来我的最小示例是错误的:我首先使用键B而不是A。但是Jon Skeet确实给了我一个主意。 I will edit if I've got anything new. 如果我有什么新东西,我会编辑。

Edit2: 编辑2:

The idea was correct. 这个想法是正确的。 I was looping over a Garbled truth table (for those interested, check this Wikipedia article ) and checking all possible ciphertexts (CT). 我正在遍历一个乱码的真值表(对于那些感兴趣的人,请查看Wikipedia文章 )并检查所有可能的密文(CT)。 The problem was if you pick an incorrect CT and use double decryption on it, it will throw the exception because the first decryption returns garbage. 问题是,如果您选择了不正确的CT并对其进行了双重解密,则它将抛出异常,因为第一次解密会返回垃圾。 A simple check on the keys in the table fixed this. 只需检查表中的键即可解决此问题。

You're using the wrong keys for decrypting. 您使用错误的密钥进行解密。 You're encrypting with key B, then encrypting the result with key A. You're then trying to decrypt that result with key B, and the final result with key A. 您正在使用密钥B加密,然后使用密钥A加密结果。然后尝试使用密钥B解密结果,并使用密钥A解密最终结果。

Each time you decrypt, you should be specifying the same key that was used to perform the "most recent" encryption operation. 每次解密时,都应指定用于执行“最新”加密操作的相同密钥。 So: 所以:

         Encrypt         Encrypt        Decrypt        Decrypt
         with B          with A         with A         with B
Plain text -> encrypted I -> encrypted II -> encrypted I -> plain text

I'd also suggest that performing these operations one statement at a time, rather than having to read from the bottom up due to doing everything in a single statement, would make it a lot easier to understand what's going on. 我还建议,在同一时间执行这些操作的一个声明,而不是从往上由于在单个语句做的一切阅读,就会使人们更方便明白发生了什么事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM