使用不同的Cipher对象解密时BadPaddingException

时间:2017-07-26 01:19:11

标签: java encryption passwords password-encryption

请原谅hackjob!编码时仍然很新,并且正在利用大量的系统输出进行故障排除,这是我在StackOverflow上的第一篇文章。谢谢你的帮助!

所以我一直在努力尝试使用javax.crypto.Cipher API加密String对象,并且我已经找到了一些成功,但只有当它使用相同的Cipher对象实例时。但是,出于我的项目的目的,我正在加密文本(String)和解密文本文件中的文本,并且每次都不会访问相同的Cipher对象。

我认为问题不在于字节数组和字符串之间的转换,因为Base64编码器似乎已经解决了这个问题。字节数组的输出在预编码和后解码时是相同的,因此在解密阶段应将其隔离为一个问题。可以做什么,以便我的decryptPW方法可以使用不同的Cipher实例(传递相同的参数)而不会触发BadPaddingException?

private static String encryptPW(String pw){
    byte[] pwBytes = pw.getBytes();
    byte[] keyBytes = "0123456789abcdef".getBytes();
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    try {
        Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ciph.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encryptedBytes = ciph.doFinal(pwBytes);
        pw = Base64.getEncoder().encodeToString(ciph.doFinal(pwBytes));

        for (byte b : encryptedBytes){
            System.out.print(b);
        }
        System.out.println();
    } catch (Exception e){
        e.printStackTrace();
    }
    return pw;
}

private static String decryptPW(String pw){
    byte[] pwBytes = Base64.getDecoder().decode(pw.getBytes());
    for (byte b : pwBytes){
        System.out.print(b);
    }
    System.out.println();

    byte[] keyBytes = "0123456789abcdef".getBytes();
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    try {
        Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
        ciph.init(Cipher.DECRYPT_MODE, keySpec, ciph.getParameters());
        pw = new String(ciph.doFinal(pwBytes));    
    } catch (Exception e){
        e.printStackTrace();
    }
    return pw;
}

再次,谢谢!

1 个答案:

答案 0 :(得分:1)

在使用CBC mode时,您需要从加密密码中保存随机初始化向量(IV)并将其提供给解密密码。

你可以在init之后从加密密码中获取它:

ciph.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] iv = ciph.getIV();

并将其提供给解密密码,例如:

ciph.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));

你需要想出一种保存IV的方法。常见的方法是使用IV为加密数据添加前缀,以便在需要初始化解密密码时可以使用它。它不需要保密。