The theme of the problem is misunderstanding of the relationship between Strings and bytes. At the end of the encrypt method, what do you think these two lines do:
byte[] ciphertext = cipher.doFinal(...
return new String(ciphertext);
The last line takes the encrypted bytes, which could be almost anything, and attempts to interpret those bytes as encoding some characters of a string. Using what encoding? String constructor with no character encoding argument uses system default encoding, which depends on JVM/OS/Locale. Lets say it is UTF-8. Are you guaranteed that there will actually be some character for the encrypted bytes? Answer: NO. Will you get the same bytes back, when you take the resulting string and call .getBytes("UTF-8"). Answer: No, there are mutliple byte sequences encoding the same characters, thus new String(bytes, "UTF-8").getBytes("UTF-8") is not guaranteed to return the bytes you started with.
In summary, don't attempt to interpret arbitrary bytes as a string. Make your encrypt method return byte[], and your decryp method take an array of bytes to decode-- then it will work.
It is not necessary to make your program work, but if you must represent the encrypted bytes as a string, consider base64 encoding, or hexadecimal encoding -- these encodings uniquely map every possible byte (or sequence of bytes) to a string.
UPDATE: here is a more concise generateKey() method. It allows you to pass the password in as an argument.
public static SecretKey generateKey(String password) {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte saltBytes[] = new byte[20];
secureRandom.nextBytes(saltBytes);
KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = factory.generateSecret(spec);
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (Exception e) {
throw new IllegalStateException("Key cant be generated !");
}
}