使用AES加密和连续解密后数据不同

时间:2013-06-23 14:37:16

标签: java cryptography aes

我想用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);
    }

}

1 个答案:

答案 0 :(得分:4)

除非assertEquals(data.hashCode(), received.hashCode())data引用同一个对象(因为字节数组从Object继承了身份哈希码方法),否则

received不太可能通过。我没有看到data来自哪里,但这可能不是这里的情况。您应该使用Arrays.equals(data, received)

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

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