Reputation: 3043
I'm implementing a simple password store using Blowfish. All was fine until I tried out a few different password/key combinations and came across numerous instances where the decrypted values were still garbage.
Below is a standalone class that demonstrates the issue. I get the following output:
'Aaaaaaa7' encrypted: 'r?—èLèdÓ,·Ã¸ÍÒ'*
'Aaaaaaa7' decrypted: 'ñü=€¼(T'*
Any idea what I need to do to guarantee it always decrypts correctly.
(Using jce.jar in JDK 1.6.0_26)
Thanks,
David
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class BlowfishTwoWayHashImpl {
static {
test();
}
public static void test() {
String key = "wibble";
String passwordToEnrypt = "Aaaaaaa7";
String enc = BlowfishTwoWayHashImpl.encryptBlowfish(passwordToEnrypt, key);
System.out.println("'" + passwordToEnrypt + "' encrypted: '" + enc + "'");
String dec = BlowfishTwoWayHashImpl.decryptBlowfish(enc, key);
System.out.println("'" + passwordToEnrypt + "' decrypted: '" + dec + "'");
}
private static final String CIPHER_NAME = "Blowfish";
public static String encryptBlowfish(String toEncrypt, String key) {
return processString(toEncrypt, key, Cipher.ENCRYPT_MODE);
}
public static String decryptBlowfish(String toDecrypt, String key) {
return processString(toDecrypt, key, Cipher.DECRYPT_MODE);
}
private static String processString(String toEncrypt, String key, int encryptDecryptMode) {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), CIPHER_NAME);
Cipher cipher;
try {
cipher = Cipher.getInstance(CIPHER_NAME);
cipher.init(encryptDecryptMode, secretKeySpec);
return new String(cipher.doFinal(toEncrypt.getBytes()));
}
catch (Exception e) {
throw new RuntimeException(e.toString());
}
}
}
Upvotes: 0
Views: 1680
Reputation: 1499760
Don't do this:
return new String(cipher.doFinal(toEncrypt.getBytes()));
You're using the platform default encoding all over the place in your code. Don't do this. It will lose data.
When you're converting genuine text to bytes (e.g. on encryption) use a specific charset - UTF-8 is a good choice. Use the same charset to decode from "encoded text" to String
.
When you're converting arbitrary binary data to text, use base64 encoding, e.g. via this public domain Base64 encoding library.
Basically, when you create a new string with the String(byte[])
or String(byte[], String)
constructors, you're saying, "This is genuine text data - please just decode it as a string." When the data is actually the result of encryption, it's not text data... it's an arbitrary bunch of bytes.
Upvotes: 4