Hullo,
I am encrypting and decrypting in Java with Blowfish.
The encryption works fine, but the decryption fails.
Here is my Java code for decrypting :
Converting bytes to hex and back is tricky. This should solve your problem. (You need to fix your string representation of encryptedString)
Output:
StackOverflow 537461636B4F766572666C6F77 [83, 116, 97, 99, 107, 79, 118, 101, 114, 102, 108, 111, 119]
J~3¹ÙÂÖ"¢ª„¨u 194A7E33B9060CD9C2D622A2AA84A875 [25, 74, 126, 51, -71, 6, 12, -39, -62, -42, 34, -94, -86, -124, -88, 117]
StackOverflow 537461636B4F766572666C6F77 [83, 116, 97, 99, 107, 79, 118, 101, 114, 102, 108, 111, 119]
Code:
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) throws Exception {
KeyGenerator keygenerator = KeyGenerator.getInstance("Blowfish");
SecretKey secretkey = keygenerator.generateKey();
String plaintextString = "StackOverflow";
System.out.println(plaintextString + " " + bytesToHex(plaintextString.getBytes()) + " " + Arrays.toString(plaintextString.getBytes()));
SecretKeySpec key = new SecretKeySpec(secretkey.getEncoded(), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(plaintextString.getBytes());
String encryptedString = bytesToHex(encrypted);
System.out.println(new String(encrypted) + " " + encryptedString + " " + Arrays.toString(encrypted));
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(hexToBytes(encryptedString));
String decryptedString = bytesToHex(decrypted);
System.out.println(new String(decrypted) + " " + decryptedString + " " + Arrays.toString(decrypted));
}
public static byte[] hexToBytes(String str) {
if (str == null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
}
return buffer;
}
}
public static String bytesToHex(byte[] data) {
if (data == null) {
return null;
} else {
int len = data.length;
String str = "";
for (int i = 0; i < len; i++) {
if ((data[i] & 0xFF) < 16)
str = str + "0" + java.lang.Integer.toHexString(data[i] & 0xFF);
else
str = str + java.lang.Integer.toHexString(data[i] & 0xFF);
}
return str.toUpperCase();
}
}
}
String encryptedString = … ;
String decryptedString = null;
SecretKeySpec key = new SecretKeySpec(myKey.getBytes(), "Blowfish");
private static byte[] linebreak = {}; // Remove Base64 encoder default linebreak
private static Base64 coder;
Cipher cipher;
try {
coder = new Base64(32, linebreak, true);
cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encryptedString.getBytes());
decryptedString = new String(coder.encode(decrypted));
} [ catch Exceptions … ]
You can use Base64 class to solve this problem.
Try this
private byte[] encrypt(String key, String plainText) throws GeneralSecurityException {
SecretKey secret_key = new SecretKeySpec(key.getBytes(), ALGORITM);
Cipher cipher = Cipher.getInstance(ALGORITM);
cipher.init(Cipher.ENCRYPT_MODE, secret_key);
return cipher.doFinal(plainText.getBytes());
}
here you can find whole class with enc/dec --- http://dexxtr.com/post/57145943236/blowfish-encrypt-and-decrypt-in-java-android
Now I have the solution !
First, there were some problems with Unicode, so I have put ISO-8859-1 everywhere. Including in the Base64 encoding and decoding.
Then, I have juggled with the variants.
Here is my Java code which works for Blowfish decryption :
String encryptedString = … ;
String decryptedString = null;
SecretKeySpec key = new SecretKeySpec(myKey.getBytes(CHARSET_ISO_8859_1), "Blowfish");
Cipher cipher;
try {
cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encryptedString.getBytes(CHARSET_ISO_8859_1));
decryptedString = new String(decrypted, CHARSET_ISO_8859_1);
} [ catch Exceptions … ]
Note that I have replaced "Blowfish"
with "Blowfish/ECB/PKCS5Padding"
for getting the Cipher
instance, but, if you do the same for the key, it fails.
The key myKey
has to be a Latin-1 string of 8 characters. This makes a key of 128 bits. The Blowfish algorithm allows bigger keys, but they fail in Java because of the USA export restriction in the JRE — the USA allow encryption but not stronger than what the NSA can break.
The CHARSET_ISO_8859_1
is a constant defined like this :
final Charset CHARSET_ISO_8859_1 = Charset.forName("ISO-8859-1");
And Charset
is java.nio.charset.Charset
.
Last but not least, I have changed my encryption Java code accordingly.
Your myKey variable lenght must be multiple of 8
You should definitely be more explicit with the Cipher
by declaring the mode and padding. How is this code getting encrypted? What is actually in the String
encryptedString
? Is it hex encoded or base64 encoded? If it isn't encoded that could definitely be a source of trouble.