I am using AES for encrypting and decrypting my password. What I am trying to implement is that that I need to store the encrypted password at the client side in the form of a cookie and then when the client logs in again into my website I need to get that encrypted password from the client side and decrypt it to check it against the unencrypted password provided by the client. The problem I am facing is that while encryption I convert byte array of the encrypted password to string using BASE64.encodeString() in java so that it could be passed to the client side. But when I get the same string from the client side, i.e from the cookie and try to decrypt it, it gives me padding error, i.e. javax.crypto.illegalBlockSizeException : Input length must be multiple of 16 when decrypting with padded cipher .
Why is it happening?
Code for encryption :
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
byte[] plainBytes = Data.getBytes(UNICODE_FORMAT);
byte[] encrypted = cipher.doFinal(plainBytes);
String encryption = Base64.encodeBase64String(encrypted);
return encryption;
Code for decryption :
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
byte[] decryptval = Base64.decodeBase64(encryptedData);
byte[] decrypted = cipher.doFinal(decryptval);
return new String(decrypted);
Is the error coming because I am passing the encrypted string to the js to be stored in cookie.?? does JS fiddle with the base64encoded string?
I STRONGLY advise against using a cipher to store/transmit passwords.
A Hash function is a much safer idea. The difference between a Cipher and a Hash is that a Cipher is reversible, whilst a Hash is one way (Plaintext -> Hashtext). Storing your users passwords on the server in a)plaintext or b)encrypted is a big no-no in terms of security.
A Hash on the other hand cannot be reversed; (Theoretically at least)
A simple hash can be done just as easily using the MessageDigest class
Getting a Hash can be pretty simple:
Message Digest md = MessageDigest.getInstance("MD5");
md.digest(input.getBytes());
The client side can then hash the plaintext password to send across to the Server. Then the server can compare hashes to authenticate and return a session token to the user which they can use for the rest of the session without having to transmit passwords all around the place.
Try using the following method to convert bytes to string while encryption -
public static String bytesToString(byte[] bytes) {
HexBinaryAdapter adapter = new HexBinaryAdapter();
String s = adapter.marshal(bytes);
return s;
}
So instead of -
String encryption = Base64.encodeBase64String(encrypted);
Use
String encryption = bytesToString(encrypted);
Similarly, during decryption use this method -
public static byte[] hexToBytes(String hexString) {
HexBinaryAdapter adapter = new HexBinaryAdapter();
byte[] bytes = adapter.unmarshal(hexString);
return bytes;
}
That is -
byte[] decryptval = hexToBytes(encryptedData);
Related
I was trying encryption in android and decryption in nodejs server. I generated an AES 128bit key and encrypt it using AES algorithm and then encrypt this generated key using RSA algorithm. Then send both to the server. But while decrypting on the server side, I think the RSA decryption works fine but have a problem in AES decryption.
I'm not getting the string in server side that I encrypted on the client side.
This is the code for the encryption on android side:
String encryptedSecretKey;
String cipherTextString;
// 1. generate secret key using AES
KeyGenerator keyGenerator = null;
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
// 2. get string which needs to be encrypted
String text = "This is the message to be encrypted";
// 3. encrypt string using secret key
byte[] raw = secretKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
cipherTextString = Base64.encodeToString(cipher.doFinal(text.getBytes(Charset.forName("UTF-8"))), Base64.DEFAULT);
// 4. get public key
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(Base64.decode(publicKeyString, Base64.DEFAULT));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(publicSpec);
// 5. encrypt secret key using public key
Cipher cipher2 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher2.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedSecretKey = Base64.encodeToString(cipher2.doFinal(secretKey.getEncoded()), Base64.DEFAULT);
Then send this to the server side.
The code for server side is given below:
var encryptedMessage = req.body.cipherText;
var encryptedAesKey = req.body.secretKey;
//printing those values
console.log("\nEncryptedMessage: \n" + encryptedMessage);
console.log("\nEncrypted key: \n" + encryptedAesKey);
var privateKey = fs.readFileSync('././Keys/privkey_server.pem', "utf8");
var bufferForAesKey = new Buffer(encryptedAesKey, "base64");
var obj = {
key: privateKey
// , padding: constants.RSA_PKCS1_PADDING
// , padding: constants.RSA/ECB/OAEPWithSHA-1
};
var decryptedAes = crypto.privateDecrypt(obj, bufferForAesKey);
console.log("Decrypted AES: " + decryptedAes);
var decryptedAesKeyString = decryptedAes.toString("base64");
console.log("Decrypted AES Key: " + decryptedAesKeyString);
var bufferForAES = new Buffer(decryptedAes, "base64");
//decrypting using AES
var bufferForEncryptedMsg = new Buffer(encryptedMessage, "base64");
var decipher = crypto.createDecipher('aes-128-cbc',bufferForAES);
decipher.setAutoPadding(false);
var dec = decipher.update(bufferForEncryptedMsg,"base64", "utf8");
dec += decipher.final("utf8");
console.log(dec);
Here the final result 'dec' is not giving the correct result but the intermediate results are same in client and server. That means, RSA works fine but have problem in AES.
The output is given below:
EncryptedMessage:
SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj
Encrypted key:
C/pa52PZda3xShrPXkHZx8OL6sW4JBEhG/ggNAoHhSVXIGt+iDq/B1ByG5yStBGF3GFJRQT0aGsG
+bZJydP7j9gTivmt99H/bxiZan4CHZnqfGKG1dJCI7ILAYZMCw7JhIcRC8qHMM4LMdF+rxRhENDe
alUfnsLWpcrX9J6fKejJ7EWnWQ1VadKqCDmrJ5xw0lBbsOpwN/vY09+VhF4WkOz8Y3cQGk+FVdz5
tr4L9/jgXlTZdOC2KVBLSH+9pvtHwMWFKKoDSAzvkil4htBjbWTqlBuEINC4I/J/4P3RX2riT5Pv
xHQi/Dv7vdBlo9AEdvWe3Ek8oBleIpmIQHXwQWknPOYghhBAVmACG/tbEQcAtbcmRLruT/XzjPJt
HNBt2HeG9JHYKNoHC3kOuJdnlGe8mv8k0Nzwj04RhEGKSmPIiu/oDgYwS0l96KIlS2ELqBlS5O0L
AJ+RBG7m0WwC9dfrufsuwu0+SPUmg5/ElXRmA3T81lXtQqQbGg8G6r/bAVFGduy4a49s/VWoylx+
/sI079IwyY0IOfwQTVGZRyDC5O1ZBjoYv2+TRo3bjG8GXNQoybkmWkhgotcqVD9mXO67D2NBsFPT
EJnw+1ApSqR7ggIAF+qsMxejFKBICBL/4J8FP4+obA07J1pWiciTRKX+G130qzIBKM08Zdaf/50=
Decrypted AES: %Kp[ϪS�/�W l��9ӊ˽��~��
B�A�
Decrypted AES Key: JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=
T�Ϝ��u��q�
���w�p���u`�̗r[`H0[tW��=��~i-�W
Here the Decrypted AES key is same as the key that we generate in android. But the final output is not giving the desired result. Is there any error in my code??
Neardupe Decrypting strings from node.js in Java? which is the same thing in the opposite direction.
[In Java] I generated an AES 128bit key and encrypt [with] it using AES algorithm and then encrypt this generated key using RSA algorithm.
No you didn't. Your Java code instantiates a KeyGenerator for AES-128, but doesn't use it to generate any key. The key you actually used (and as you say the server correctly decrypted from RSA-OAEP) is 32 bytes, corresponding to AES-256.
But your main problem is that createDecipher takes a password NOT the key. Per the doc
crypto.createDecipher(algorithm, password[, options])
The implementation of crypto.createDecipher() derives keys using the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt.
You passed what is actually a key as a password; this results in nodejs using a key that is completely different from the one used in Java and thus getting completely wrong results. You should instead use createDecipheriv which does take the key, and IV (Initialization Vector).
And that is your other problem. To decrypt you must use the same IV as encrypt did, normally by including the IV with the ciphertext sent from the sender to receiver, but you don't. As a result the following (simplified) code cannot decrypt the first 16 bytes of your data, but does the rest.
const crypto = require('crypto');
msg = Buffer.from('SfosHg+cTrQXYUdF0FuqCJMHgfcP13ckp2L0B9QqOcl8UtWnnl8fLi5lxgR2SKOj','base64');
aeskey = Buffer.from('JUtwW8+qU6Mv/FcgbMbkOdOKy72pun4B490KQrRB4QQ=','base64');
dec = crypto.createDecipheriv('aes-256-cbc',aeskey,Buffer.alloc(16)/*this should be the IV*/);
console.log(dec.update(msg,'','latin1')+dec.final('latin1'));
// I used latin1 instead of utf8 because the garbaged first block
// isn't valid UTF-8, and the rest is ASCII which works as either.
->
Y;øï«*M2WÚâeage to be encrypted
// some garbaged chars are control chars and Stack (or browser?)
// may not display them but there really are 16 in total
As an aside, the statement in the doc that 'Initialization vectors [must] be unpredictable and unique ... [but not secret]' is correct for CBC mode, but not some other modes supported by OpenSSL (thus nodejs) and Java. However, that's not a programming Q and thus offtopic here; it belongs on crypto.SX or possibly security.SX where it has already been answered many times.
I have encrypted the session id at server side using AES but not able to decrypt the encrypted session id at client side, As there isn't any AES library defined for GWT to support AES decryption in java.
The code snippet for AES encryption at server side is :
public static String encrypt(String sessionId)
{
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String key = "Abcdefghijklmnop";
final SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
final String encryptedSessionId = Base64.encodeBase64String(cipher.doFinal(sessionId.getBytes()));
return encryptedSessionId;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
For decryption I am trying with the code provided in this link :
http://reassess.blogspot.in/2009/07/gwt-and-aes-decryption.html
But this isnt working. Please provide any solution if anyone has.
I have tried encryption and decryption in DES but I need to use AES.
AES is not be supported on client side for GWT, but you can use TripleDES. TripleDES is also very much secure implementation.
Here it's another similar question
Here are list of known issues for GWT-crypto.
https://code.google.com/archive/p/gwt-crypto/issues
See #1 issue- AES Encrypted content cant' be decrypted by Java AES Decryptor & Vice Versa
This might be a duplicate of this answered question, but I can't seem to get the same results. Hoping for some guidance here.
JSEncrypt (client)
let encrypt = new Encrypt.JSEncrypt();
encrypt.setPublicKey(this.publicKey); // retrieved from server
encrypt.encrypt(password);
BouncyCastle (server) - RSA key generation
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(1024);
KeyPair pair = generator.generateKeyPair();
PublicKey pubKey = pair.getPublic();
PrivateKey privKey = pair.getPrivate();
// returned to client
String publicKeyStr = new String(Base64.encodeBase64(pubKey.getEncoded()));
String privateKeyStr = new String(Base64.encodeBase64(privKey.getEncoded()));
BouncyCastle (server) - Decryption
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// org.apache.commons.codec.binary.Hex
byte[] cipherText = cipher.doFinal(Hex.decodeHex(encrypted.toCharArray()));
decrypted = new String(cipherText, BaseConstant.ENC_UTF8);
Error
org.apache.commons.codec.DecoderException: Illegal hexadecimal character I at index 0
at org.apache.commons.codec.binary.Hex.toDigit(Hex.java:178)
at org.apache.commons.codec.binary.Hex.decodeHex(Hex.java:89)
One thing I noticed is the length of encrypted text by JSEncrypt, which is 172, while encryption at server side produces 256.
The answered question mentioned to use RSA/None/PKCS1Padding, which I had already set. What else could I be missing?
The error occurs in Hex.decodeHex() method, which means that your data is not a Hex encoded string.
JSEncrypt.encrypt() method returns the encrypted data in Base64 (instead of Hex string). In order to decrypt it, you must decode it from base64 format.
So instead of:
byte[] cipherText = cipher.doFinal(Hex.decodeHex(encrypted.toCharArray()));
Do this:
byte[] cipherText = cipher.doFinal(Base64.decodeBase64(encrypted.toCharArray()));
You can also solve this problem just from the client side. See the code below:
let encrypt = new Encrypt.JSEncrypt();
encrypt.setPublicKey(this.publicKey);
encrypt.getKey().encrypt(password);
Just add getKey() after encrypt. It worked for me! I encrypted my password into Hex string using this approach.
I have to implement basic encryption in my program. I can use Base64 it was rejected by the client. So I am using the following methods. The problem which I am facing is the there are special characters in the encrypted which are resulting in exceptions. Can I change this code to somehow encrypt into plain text without special characters.
protected static byte[] encrypt(String text)
{
try
{
String key = "6589745268754125";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes());
return encrypted;
}
catch(Exception ex)
{
WriteLog("Encryption Failed");
WriteLog(ex.getMessage());
return null;
}
}
protected static String decrypt(byte[] pass)
{
try
{
String key = "6589745268754125";
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(pass));
return decrypted;
}
catch(Exception ex)
{
WriteLog("Encryption Failed");
WriteLog(ex.getMessage());
return null;
}
}
The exception message says "Given final block not properly padded"
javax.crypto.BadPaddingException: Given final block not properly padded
so, basically you don't know about encryption and have the problem that your client wants encryption
ok, a quick headsup:
encoding: transforming an input to an output that holds identical information but in another representation ... ex: 1,2,3 -> a,b,c
as you can see the output looks differently but holds the same information
please note that no secret information is necessary to encode/decode
encryption: might look similar at first glance but here you need some secrets ... an encryption takes 2 inputs ... a secret and the input data
the resulting output can be decrypted, but ONLY if you have the corresponding secret
if your client wants you to encrypt something, make sure that thing can be represented as bytes ... encrypting a string... not good... encrypting a string that has been transformed into < insert arbitrary byte encoding here, for example unicode > ... ok
encryptions usually handle bytes (let's not care about historic ciphers here)
when you decide for an encryption/cipher you have to know that there are essentially 2 distinct groups: symetric and asymetric
symetric: the same key (read secret) you use to encrypt will be needed for decryption
asymetric: there are keypairs consisting of a public and a private part (public/private key) the public part is used for encryption, the private part is used for decryption ... makes no sense unless you have different parties that need to exchange keys
asymetric ciphers are usually used to encrypt decrypt the keys for symetric ciphers because they are SLOW while symetric ciphers usually are FAST
asymetric ciphers are not intended to encrypt large amounts of data
symetric ciphers are intended for bulk data
if your goal is just to keep an information encrypted while it is laying around on a harddisk, a symetric cipher is what you want
you will need a key for the cipher to operate ... and... you will have the problem where to store it ... so if you can, have the user enter a sufficiently complex password ... use the password and a function called PBKDF2 with a sufficiently high iteration count (sufficiently high= increase this number until the process takes either a few seconds if you only need this on startup, or until your users start complaining about the delay) to make binary key from the password.
use this key for AES in GCM mode (symetric cipher)
the cipher will want something called IV or initialization vector ...
the iv is no secret, you may prepend this thing to your ciphertext as clear text information
the iv needs to be the size of one block of your cipher, so in the case of AES 128 bit = 16 byte
so your IV when encrypting is a 16 byte (unique) random number (means that you may not use an IV two times or more: persist the used IVs and when getting a new one, check if it was already stored, if yes startover IV generation, if no, store it and then use it)
when decrypting, read the prepended cleartext IV from your file (first 16 byte)
if you just want to store the ciphertext on disk, write it into a binary file
if the file has to contain only printable text apply an encoding like base16/32/64 before writing your bytes to the file and decode into a byte array before decrypting (unless your data is too big for that, then you will have to find/write a stream wrapper that will add/strip encoding for you)
If the client doesn't like Base64, then try Base32 or Base16 (= hex). They are less common but well defined alternatives to Base64.
You might also find out exactly why the client doesn't want you to use Base64.
You should Base64 the encrypted content. It's usual technique by the way.
I guess the client's problem wasn't Base64 format itself but the fact, that Base64 isn't (a strong) encryption.
The problem was padding. I had use AES/CBC/NoPadding and make sure that my strings are multiple of 16 bytes. So in addition to changing the ecryption and decryption I had to add two methods. One to add \0 i.e. implicit null terminators to the end end of the text to make it a multiple of 16 and another to remove them after decryption. So the final version is like this.
public class crypto {
static String IV = "AAAAAAAAAAAAAAAA";
static String plaintext = "my non padded text";
static String encryptionKey = "0123456789abcdef";
public static void main(String[] args)
{
byte[] cipher = encrypt(plaintext);
String decrypted = decrypt(cipher);
}
protected static String covertto16Byte(String plainText)
{
while(plainText.length()%16 != 0)
plainText += "\0";
return plainText;
}
protected static String removePadding(String plainText)
{
return plainText.replace("\0","");
}
protected static byte[] encrypt(String plainText)
{
try
{
String _plaintText_16 = covertto16Byte(plainText);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(_plaintText_16.getBytes("UTF-8"));
} catch (Exception ex)
{
//catch mechanism
return null;
}
}
protected static String decrypt(byte[] cipherText)
{
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return removePadding(new String(cipher.doFinal(cipherText), "UTF-8"));
} catch (Exception ex)
{
//catch mechanism
return null;
}
}
}
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 use new 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 url
In 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:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Test {
private static String strkey ="Blowfish";
private static Base64 base64 = new Base64(true);
//encrypt using blowfish algorithm
public static String 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 base64.encodeToString(cipher.doFinal(Data.getBytes("UTF8")));
}
//decrypt using blow fish algorithm
public static String decrypt(String encrypted)throws Exception{
byte[] encryptedData = base64.decodeBase64(encrypted);
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);
}
public static void main(String[] args) throws Exception {
String data = "will this work?";
String encoded = encrypt(data);
System.out.println(encoded);
String decoded = decrypt(encoded);
System.out.println(decoded);
}
}
Hope this answers your questions.
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.
The problem is with the way you are creating String instances out of the raw encrypted byte[] data. You need to either use binhex encoding like that provided by javax.xml.bind.DatatypeConverter via the parseHexBinary and printHexBinary methods or base 64 using the parseBase64Binary and printBase64Binary 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.