使用Java中的PBEWithHMACSHA256andaes256加密要存储在文件中的密码

使用Java中的PBEWithHMACSHA256andaes256加密要存储在文件中的密码,java,encryption,Java,Encryption,我想加密一个密码,该密码需要存储在一个平面文件中,以便java应用程序访问。我使用了的公认答案对我的解决方案进行建模,它是有效的。因为我对加密算法几乎一无所知,一旦我读到DES有多弱,我想选择另一种算法,我选择了pbewithhmacsha256andaes256。当我使用pbewithmd5和des时 pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20)); .... pbeCipher.init(Cip

我想加密一个密码,该密码需要存储在一个平面文件中,以便java应用程序访问。我使用了的公认答案对我的解决方案进行建模,它是有效的。因为我对加密算法几乎一无所知,一旦我读到DES有多弱,我想选择另一种算法,我选择了
pbewithhmacsha256andaes256
。当我使用
pbewithmd5和des时

pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
....
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
足够解密字符串,但使用此算法,我得到以下异常:

java.security.InvalidAlgorithmParameterException: Missing parameter type: IV expected
    at com.sun.crypto.provider.PBES2Core.engineInit(PBES2Core.java:252)
    at javax.crypto.Cipher.implInit(Cipher.java:806)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
我能让解密工作的唯一方法是,我将加密密码的算法参数传递给解密密码,如下所示:

pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
AlgorithmParameters ap = pbeCipher.getParameters();
....
pbeCipher.init(Cipher.DECRYPT_MODE, key, ap);
这对我不起作用,因为如果同时重新启动应用程序,我需要能够解密。
所以,我的问题是:这就是这个算法应该如何工作的,在这种情况下,我应该选择一个不同的更强的(或者我应该麻烦一下),还是我做错了什么?

AES密码需要一个额外的算法参数-IV。你可以将其视为另一个SALT(可以是随机的,与密码一起存储)。alg规范的IV应为16字节长

public static String encrypt(String text) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException, InvalidAlgorithmParameterException {
    Cipher cipher = Cipher.getInstance(ENC_ALG);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALG);

    KeySpec keySpec = new PBEKeySpec(PASSWORD.toCharArray(), SALT, 65536, 256);
    SecretKey key = keyFactory.generateSecret(keySpec);

    IvParameterSpec ivSpec = new IvParameterSpec(IV);    
    PBEParameterSpec paramSpec = new PBEParameterSpec(SALT, 0,ivSpec);

    cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
    byte[] encrypted = cipher.doFinal(text.getBytes());

    return Base64.getEncoder().encodeToString(encrypted);
}

public static String decrypt(String encrypted) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
    Cipher cipher = Cipher.getInstance(ENC_ALG);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALG);

    KeySpec keySpec = new PBEKeySpec(PASSWORD.toCharArray(), SALT, 65536, 256);
    SecretKey key = keyFactory.generateSecret(keySpec);
    IvParameterSpec ivSpec = new IvParameterSpec(IV);    
    PBEParameterSpec paramSpec = new PBEParameterSpec(SALT, 0, ivSpec);
    cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
    byte[] decoded = Base64.getDecoder().decode(encrypted);
    byte[] decrypted = cipher.doFinal(decoded);
    return new String(decrypted);
}
是启动加密和解密过程所需的固定大小的随机数据。解密时,这段数据需要与加密时使用的数据相同

使用pbewithmd5和des时,IV来自密码,因此不需要在解密时指定

但是,对于pbewithhmacsha256andaes256IV在每次加密时都是随机的(与密码无关),因此需要在解密时提供

您可以使用
pbeCipher.getIV()从加密密码中对其进行绘图


通常,IV被预先设置为加密数据。它不需要保密。

当您使用旧代码和新的加密参数时,会出现什么异常?@GabrielVince I已经用异常更新了问题。注意,3参数
PBEParameterSpec
在Java 8中是新的。PBEParameterSpec是从Java 1.4开始的。然而,这实际上是一个使用Java8的示例,并非所有方法(或构造函数)都存在于旧版本中。但是基本思想仍然有效——AES密码期望指定IV,我建议在加密时也明确地这样做。