One approach might surely be to remove redundant code for the SecretKey and to add a default getter:
private static final String FACTORY_ALGORITHM = "PBKDF2WithHmacSHA256";
private static final String KEY_ALGORITHM = "AES";
private static final int KEYSPEC_ITERATION_COUNT = 65536;
private static final int KEYSPEC_LENGTH = 256;
//TODO describe your default implementation or use better member names (mine are a bit too plain - this would make this javadoc obsolete)
private SecretKey getDefaultSecretKey(final String password, final byte[] salt){
return getSecretKey(password, salt, FACTORY_ALGORITHM, KEY_ALGORITHM, KEYSPEC_ITERATION_COUNT, KEYSPEC_LENGTH);
}
private SecretKey getSecretKey(final String password,
final byte[] salt,
final String factoryAlgorithm,
final String keyAlgorithm,
final int iterationCount,
final int keyLength){
SecretKeyFactory factory = SecretKeyFactory.getInstance(factoryAlgorithm);
return new SecretKeySpec(factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength)).getEncoded(), keyAlgorithm); //thanks alot for the bug report
}
that would lead to a very readable version of your code:
public EncryptedData encrypt(String password, String data) throws Exception {
//you DONT handle Exceptions - so you let other people do the work you're supposed to do
//thats ok for me =)
SecretKey secret = getDefaultSecretKey(password, generateSalt());
Cipher cipher = getDefaulCipher(); //analogy towards getDefaultSecretKey - now you know how it would work
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] initVector = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(data.getBytes("UTF-8")); //FIXME: no hardcoded Byte-Conversion
return new EncryptedData(getBase64String(salt), getBase64String(initVector), getBase64String(ciphertext));
}
public String decrypt(String password, EncryptedData b) throws Exception {
//yeah exceptions handling is other peoples duty, not mine
SecretKey secret = getDefaultSecretKey(password, getBase64Bytes(b.getSaltString()));
byte[] initVector = getBase64Bytes(b.getInitVector());
byte[] cipherText = getBase64Bytes(b.getCipherText());
Cipher cipher = getDefaulCipher(); //as mentioned above
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initVector));
return new String(cipher.doFinal(cipherText), "UTF-8"); //FIXME: no hardcoded Byte-Conversion
}
Things left (see comments in the code above):
- Improved exception handling;
- No hardcoded Byte-Conversion;
- Default getter for Cipher (following the example from
getDefaultSecretKey())
----), delete the code, paste it in cleanly, select it, and press Ctrl-K. \$\endgroup\$