2016-10-10 164 views
2

我想对我需要存储在平面文件中的密码进行加密,以便由我的Java应用程序访问。我用this question的接受答案来模拟我的解决方案,并且它工作。由于我对加密算法几乎一无所知,一旦我读到DES的弱点,我想选择另一种算法,并且我选择了PBEWithHmacSHA256AndAES_256。当我使用PBEWithMD5AndDES使用Java中的PBEWithHmacSHA256AndAES_256加密要存储在文件中的密码

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

因为我需要能够如果应用程解密这并不为我工作同时重新启动。 所以,我的问题:这就是这个算法应该如何工作,在这种情况下,我应该选择一个更强大的(或者我应该打扰一切),还是我做错了什么?

+0

当你使用旧的代码与新的加密参数时,你会得到什么异常? – gusto2

+0

@GabrielVince我已经更新了例外的问题。 – Mitio

回答

2

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); 
} 
+0

请注意,3参数'PBEParameterSpec'是Java 8中新增的。 –

+0

PBEParameterSpec自Java 1.4起。但是 - 这实际上是一个使用Java 8的示例,并不是所有的方法(或构造函数)都可能存在于旧版本中。但基本思想仍然有效 - AES密码希望指定IV,并且我建议在加密时也明确这样做。 – gusto2

+0

谢谢,当我指定一个IV时像一个魅力。 – Mitio

2

一种Initialization Vector (IV)是一个固定大小的片以启动加密&解密处理所需要的随机数据。解密时,这段数据需要与加密时使用的相同。

当使用PBEWithMD5AndDESIV从密码导出的,并且因此不需要在解密指定。

然而,随着PBEWithHmacSHA256AndAES_256IV是随机的与每个加密(独立于密码),并且因此需要被设置在解密。

可以从加密密与pbeCipher.getIV();

通常IV是GRAP它预先计划的加密的数据。它不需要保密。

相关问题