【问题标题】:Data differs after encryption and consecutive decryption with AES使用 AES 加密和连续解密后数据不同
【发布时间】:2013-06-24 14:19:32
【问题描述】:

我想用 AES 加密和解密整数,但做不到。

为了测试基本的加密过程,我编写了一个简单的方法,它接受输入数据,使用相同的参数对其进行加密和解密,然后返回结果。

这是我失败的 JUnit 测试用例,它检查输入和输出数据是否相等。

    @Test
public void test4() throws UnsupportedEncodingException {

    Random random = new Random();

    SecretKey secretKey = Tools.generateKey("secretKey".getBytes("UTF-8"));

    byte[] initializationVector = Tools.intToByteArray(random.nextInt()); 
    // ensuring that the initialization vector has the correct length
    byte[] ivHash = Tools.hashMD5(initializationVector);

    int value = random.nextInt();
    byte[] input = Tools.intToByteArray(value);

    byte[] received = Tools.enDeCrypt(input, secretKey, ivHash);        
    assertEquals(data.hashCode(), received.hashCode());
}

方法 generateKey:

public static SecretKeySpec generateKey(byte[] secretKey) {

    try {
        // 256 bit key length
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(secretKey);
        byte[] key = md.digest();
        return new SecretKeySpec(key, "AES");
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}

int -> byte[] 转换方法:

public static byte[] intToByteArray(int a) {
    // block size is 128 bit, thus I append zeros 

    byte[] intByte = ByteBuffer.allocate(4).putInt(a).array();
    byte[] longerIntByte = new byte[16];
    for (int i = 0; i < 4; i++) {
        longerIntByte[i] = intByte[i];
    }
    for (int i = 4; i < longerIntByte.length; i++) {
        longerIntByte[i] = 0;
    }
    return longerIntByte;
}

下面是加解密代码:

public static byte[] enDeCrypt(byte[] data, SecretKey secretKey,
        byte[] initialisationVector) {

    try {
        IvParameterSpec ivSpec = new IvParameterSpec(initialisationVector);
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encrypted = cipher.doFinal(data);

        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;

    } catch (NoSuchAlgorithmException | NoSuchPaddingException
            | InvalidKeyException | InvalidAlgorithmParameterException
            | IllegalBlockSizeException | BadPaddingException e) {
        throw new RuntimeException(e);
    }

}

【问题讨论】:

    标签: java cryptography aes


    【解决方案1】:

    assertEquals(data.hashCode(), received.hashCode()) 不太可能通过,除非 datareceived 引用同一个对象(因为字节数组从 Object 继承身份哈希码方法)。我看不出data 来自哪里,但这里可能不是这样。你应该使用Arrays.equals(data, received)

    除此之外,这里还有各种加密问题:

    • 随机对于加密目的来说不够“随机”;你应该使用 SecureRandom。
    • 使用普通 SHA-256 的密钥派生是可疑的。您应该考虑使用专门为此设计的密钥派生算法,例如 PBKDF2。
    • 带有 256 位密钥的 AES 并不总是优于 128 位密钥。检查this page。在这种情况下,它完全是伪造的,因为密码短语很少达到 128 位的熵。
    • 随机 IV - 很好,但是当您可以直接使用 SecureRandom.nextBytes() 时,为什么要跳过箍。散列 IV 不会增加任何有用的东西。
    • 当您可以让库处理它时,没有理由进行手动零填充。只需指定 PKCS5Padding 而不是 NoPadding。

    【讨论】:

    • * 随机数只是用来测试的128 位块长度 * 我在使用 PKCS5 时遇到问题(BadPaddingException:给定最终块未正确填充)
    • IV 不需要是随机的,它只需要是唯一且不可预测的。
    猜你喜欢
    • 2016-04-25
    • 2015-01-20
    • 2014-01-05
    • 2019-01-06
    • 1970-01-01
    • 2019-12-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    相关资源
    最近更新 更多