繁体   English   中英

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

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

因此,这种特殊情况非常普遍,但是我的问题与通常提出的问题略有不同。

我已经定义了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);
    }

现在,如果我像这样执行一次解密:

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]))
                                )
                        )));

字节数组输出就可以了。 而如果我执行双重加密/解密:

        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]))
                                    )
                            ))));

我得到了著名的javax.crypto.BadPaddingException: Given final block not properly padded Exception。 请注意, ab只是整数(假设它们都为0)。 当前,IVBytes只是一个大小为16的空字节数组,用new byte[16] aKeysbKeys都是带有AES加密(随机)字符串(长度为32个字节)的String数组。

这些是我使用的辅助函数(将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;
    }

我怀疑第一次解密的​​输出会使密文格式错误,以至于外部会引发异常。 我检查了大小,外部部分输出了32个字节,因此应该可以。 这不符合PKC5Padding吗?

任何帮助深表感谢。

编辑:

看来我的最小示例是错误的:我首先使用键B而不是A。但是Jon Skeet确实给了我一个主意。 如果我有什么新东西,我会编辑。

编辑2:

这个想法是正确的。 我正在遍历一个乱码的真值表(对于那些感兴趣的人,请查看Wikipedia文章 )并检查所有可能的密文(CT)。 问题是,如果您选择了不正确的CT并对其进行了双重解密,则它将抛出异常,因为第一次解密会返回垃圾。 只需检查表中的键即可解决此问题。

您使用错误的密钥进行解密。 您正在使用密钥B加密,然后使用密钥A加密结果。然后尝试使用密钥B解密结果,并使用密钥A解密最终结果。

每次解密时,都应指定用于执行“最新”加密操作的相同密钥。 所以:

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

我还建议,在同一时间执行这些操作的一个声明,而不是从往上由于在单个语句做的一切阅读,就会使人们更方便明白发生了什么事情。

暂无
暂无

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

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