I am able to encrypt data however when decrypting it i am getting the following error:
Error
HTTP Status 500 - Request processing failed; nested exception is javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
Here is my Encryption and Decryption code
//secret key 8
private static String strkey ="Blowfish";
UPDATED
//encrypt using blowfish algorithm
public static byte[] encrypt(String Data)throws Exception{
SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, key);
return (cipher.doFinal(Data.getBytes("UTF8")));
}
//decrypt using blow fish algorithm
public static String decrypt(byte[] encryptedData)throws Exception{
SecretKeySpec key = new SecretKeySpec(strkey.getBytes("UTF8"), "Blowfish");
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encryptedData);
return new String(decrypted);
}
If you run your encrypt and decrypt methods in a main method, it will work. But if the results of encrypt are put into a url and then the url parameter is decrypted, it will fail.
After encryption, the byte array contains values that are outside the character set of URLS (non-ascii), so this value gets encoded when it is stuffed into a url. And you you receive a corrupted version for decryption.
As an example, when I created a string from an encrypted byte array, it looked like this
Ž¹Qêz¦
but if I put it into a URL it turns intoŽ%0B¹Qêz¦
.The fix, as suggested in other comments, is to add a encode / decode step. After encryption, the value should be encoded to a format which contains ascii characters. Base 64 is an excellent choice. So you return encrypted and encoded value in the url. When you receive the param, first decode then decrypt, and you'll get the original data.
Here are some notes on the implementation.
Use a library like commons codec. It is my weapon of choice, this class specifically http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html.
In the class that does encryption and decryption, have a shared instance of
Base64
. To instantiate it usenew Base64(true);
this produces url safe strings.Your encrypt and decrypt method signatures should accept and return strings, not byte arrays.
So the last line of your encrypt would become something like
return base64.encodeToString(cipher.doFinal(Data.getBytes("UTF8")));
You can now safely pass the encrypted value in a urlIn your decrypt, you first step is to decode. So the first line would become something like
byte[] encryptedData = base64.decodeBase64(encrypted);
I just took your code and added some base 64 stuff, the result looks like this:
Hope this answers your questions.
The problem is with the way you are creating
String
instances out of the raw encryptedbyte[]
data. You need to either use binhex encoding like that provided byjavax.xml.bind.DatatypeConverter
via theparseHexBinary
andprintHexBinary
methods or base 64 using theparseBase64Binary
andprintBase64Binary
methods of the same object.One other word of advice, never rely on the default mode and padding, always be explicit. Use something like
Cipher.getInstance("Blowfish/CBC/PKCS5Padding")
depending on what your needs are.You can't create a String out of random (in this case encrypted) bytes like you're doing in the last line of your encrypt method - you need to create a Base64 encoded string instead (which you then need to decode back to a byte array in the decrypt method). Alternatively, just have your encrypt method return a byte array and have your decrypt method accept a byte array as its parameter.