In the following snippet I try to print encrypted array in a simple string format.
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
String input = "password";
byte encrypted[] = cipher.doFinal(input.getBytes());
String s = new String(encrypted);
System.out.println(s);
But what I get is `┐╫Y²▓ô┴Vh¬∙:╪⌡¶ . Why is it ? How can I print it in the proper string format ?
You could use Base64 encoding from common-codec.
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
String input = "password";
byte encrypted[] = cipher.doFinal(input.getBytes());
System.out.println(new String(Base64.encodeBase64(encrypted)));
Output:
8KA8ahr6INnY4qqtzjAJ8Q==
Encode the bytes in Base64 encoding (How do I convert a byte array to Base64 in Java?)
Or Hex: How to convert a byte array to a hex string in Java?
System.out.println( Hex.encodeHexString( bytes ) );
Most cryptographic algorithms (including blowfish) deal with binary data meaning that it will take binary data in and split out binary data that has been transformed by the algorithm (with the provided specs).
Binary data, as you know is != to string data, however binary data can be represented as string data (using hex, base64, etc).
If we look at your example code we can see this line:
byte encrypted[] = cipher.doFinal(input.getBytes());
This is what it is doing step by step:
It first converts string data into a binary data equivalent using the platform's default charset (NOT RECOMMENDED, but irrelevant).
It is passing the binary data (in form of a byte array) to the method doFinal().
The doFinal() method is processing this byte array via the specifications specified in the statements prior to this line (Blowfish, encryption).
The doFinal() statement is returning a byte array which represents the processed (encrypted, in your case) data.
The fact that the data originally came from a string is no longer relevant because of the nature of the encryption operation does not account for the source or type of the data. The encrypted byte array now contains data that may not be valid charset encoded string. Trying to use a character set to decode the string would most likely result in garbage output as the binary data is no longer a valid string.
However, binary data can be represented directly by outputting the VALUE of the actual bytes rather than what the charset equivalent mapping is (e.g A byte may have the value of 97, which represented in hex is: 0x61 but decoded via ASCII results in the character 'a').
Consider this code to output your encrypted data in hex:
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
String input = "password";
byte encrypted[] = cipher.doFinal(input.getBytes());
StringBuilder str = new StringBuilder();
for(byte b:encrypted){
str.append(String.format("%02x", b));
}
String encData = str.toString();
System.out.println(encData);
P.S: Don't use getBytes() without any arguments! Supply your own charset like UTF-8. Do as follows:
byte encrypted[] = cipher.doFinal(input.getBytes(Charset.forName("UTF-8")));
You can try with:
new String(bytes, StandardCharsets.UTF_8)
Related
I am finding it difficult to convert a piece of code to php from java.
I searched on the internet about the meaning of each line of code written in my java code example but I didn't find any.
I want to understand what each line does in this particular example.
This is what I tried.
function my_aes_encrypt($key, $data) {
if(16 !== strlen($key)) $key = hash('MD5', $key, true);
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_ECB, str_repeat("\0", 16)));
}
function my_aes_decrypt($str, $key){
$str = base64_decode($str);
$str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB);
$block = mcrypt_get_block_size('rijndael_128', 'ecb');
$pad = ord($str[($len = strlen($str)) - 1]);
$len = strlen($str);
$pad = ord($str[$len-1]);
return substr($str, 0, strlen($str) - $pad);
}
Convert from Java to PHP
//provided key
byte[] keyBinary = DatatypeConverter.parseBase64Binary("r/RloSflFkLj3Pq2gFmdBQ==");
SecretKey secret = new SecretKeySpec(keyBinary, "AES");
// encrypted string
byte[] bytes = DatatypeConverter.parseBase64Binary("IKWpOq9rhTAz/K1ZR0znPA==");
// iv
byte[] iv = DatatypeConverter.parseBase64Binary("yzXzUhr3OAt1A47g7zmYxw==");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String msisdn = new String(cipher.doFinal(bytes), "UTF-8");
It would be great if you guys let me know the details of each line written in Java.
The functionalities of the Java- and the PHP-code differ significantly. First of all, the Java-code contains only the decryption part, whereas the PHP-part contains both, the encryption- and decryption part. Contrary to the Java-code, in the PHP-my_aes_decrypt-method the insecure ECB-mode (https://crypto.stackexchange.com/questions/20941/why-shouldnt-i-use-ecb-encryption) seems to be used instead of the CBC-mode and thus, no IV is involved. Less important, but nonetheless different, the key doesn't seem to be base64-encoded because it's not decoded anywhere. In addition, in the PHP-code deprecated methods like mcrypt_encrypt (http://php.net/manual/de/function.mcrypt-encrypt.php) or cryptographic weak algorithms like MD5 (https://en.wikipedia.org/wiki/MD5) are used.
If I get it right, the Java code is the reference code and you need the PHP-counterpart. Thus, I focus on the Java-code and ignore the differing and outdated PHP-code completely.
In the Java-code, the key, the data and the IV, all base64-encoded, become decoded and then, the encrypted data are decrypted using these decoded data.
A possible PHP-counterpart for the decryption could be:
<?php
$keyBinary = base64_decode('r/RloSflFkLj3Pq2gFmdBQ=='); // decode base64-encoded key in a string (internally, PHP strings are byte arrays)
$bytes = base64_decode('IKWpOq9rhTAz/K1ZR0znPA=='); // decode base64-encoded encrypted data in a string
$iv = base64_decode('yzXzUhr3OAt1A47g7zmYxw=='); // decode base64-encoded IV in a string
$msisdn = openssl_decrypt($bytes, 'AES-128-CBC', $keyBinary, OPENSSL_RAW_DATA, $iv); // decrypt data using AES-128, CBC-mode and PKCS7-Padding (default-padding)
// - when OPENSSL_RAW_DATA is specified raw data are returned, otherwise base64-encoded data (= default)
// - when OPENSSL_ZERO_PADDING is specified no padding is used, otherwise PKCS7-padding (= default)
// - The value XXX in AES-XXX-CBC is determined by the length of the key in Bit used in the Java-code,
// e.g. for a 32 Byte (256 Bit)-key AES-256-CBC has to be used.
print $msisdn."\n"; // Output: 1234567 // print decrypted data
The desired explanation for the Java-code can be found in the comments:
//provided key
byte[] keyBinary = DatatypeConverter.parseBase64Binary("r/RloSflFkLj3Pq2gFmdBQ=="); // decode base64-encoded key in a byte-array
SecretKey secret = new SecretKeySpec(keyBinary, "AES"); // create AES-key from byte-array (currently 16 Byte = 128 Bit long)
// encrypted string
byte[] bytes = DatatypeConverter.parseBase64Binary("IKWpOq9rhTAz/K1ZR0znPA=="); // decode base64-encoded encrypted data in a byte-array
// iv
byte[] iv = DatatypeConverter.parseBase64Binary("yzXzUhr3OAt1A47g7zmYxw=="); // decode base64-encoded IV in a byte-array
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // create cipher-instance for using AES in CBC-mode with PKCS5-Padding (Java counterpart to PKCS7)
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv)); // initialize cipher-instance for decryption with specified AES-key and IV (the latter created from corresponding byte-array)
String msisdn = new String(cipher.doFinal(bytes), "UTF-8"); // decrypt data using AES-128 (128 determined by length of used key in Bit), CBC-mode and PKCS5-Padding,
// and put them in a UTF-8 string
System.out.println(msisdn); // Output: 1234567 // print decrypted data
The PHP-encryption part could be:
<?php
$keyBinary = base64_decode('r/RloSflFkLj3Pq2gFmdBQ==');
$msisdn = '1234567'; // plain text
$iv = openssl_random_pseudo_bytes(16); // generate random IV
//$iv = base64_decode('yzXzUhr3OAt1A47g7zmYxw=='); // use this line for tests with your base64-encoded test-IV yzXzUhr3OAt1A47g7zmYxw==
$bytes = openssl_encrypt($msisdn, 'AES-128-CBC', $keyBinary, OPENSSL_RAW_DATA, $iv); // encrypt data using AES-128, CBC-mode and PKCS7-Padding (default-padding)
$ivBase64 = base64_encode($iv); // base64-encode IV
$bytesBase64 = base64_encode($bytes); // base64-encode encrypted data
print $ivBase64."\n".$bytesBase64."\n"; // print base64-encoded IV and encrypted data
I am currently playing with Cipher to create a solution using a key that is always the same. I know this is not the most secure solution but it is what I have been asked to do. I am supposed to use AES256 and EBC, but I can not encrypt correctly. The problem is that I've got unknown characters.
private static String encrypt(String text) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException
{
String keyString = AESEncryption.convertToUTF8("8DJE7K01U8B51807B3E17D21");
text = AESEncryption.convertToUTF8(text);
byte[]keyValue = Base64.getEncoder().encode(keyString.getBytes(StandardCharsets.UTF_8));
Key key = new SecretKeySpec(keyValue, "AES");
Cipher c1 = Cipher.getInstance("AES/ECB/PKCS5Padding");
c1.init(Cipher.ENCRYPT_MODE, key);
byte[] encodedText =Base64.getEncoder().encode(text.getBytes(StandardCharsets.UTF_8));
System.out.println("Encoded text: "+new String(encodedText,StandardCharsets.UTF_8));
byte[] encVal = c1.doFinal(encodedText);
System.out.println("Encoded val: "+new String(encVal,StandardCharsets.UTF_8));
return new String(encVal);
}
Edit: Sorry first time asking. I will give you the full scope. Afterwards I try to decrypt with the following code(I know that I have repeated code, I will clean it) But when I decrypt the output obtained by the encrypt method I recieve the following error. The message I am trying to encrypt and decrypt is "Hola"
public static String desEncrypt(String text) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
String keyString = AESEncryption.convertToUTF8("8DJE7K01U8B51807B3E17D21");
byte[] keyValue = Base64.getEncoder().encode(keyString.getBytes(StandardCharsets.UTF_8));
Key key = new SecretKeySpec(keyValue, "AES");
Cipher c1 = Cipher.getInstance("AES/ECB/PKCS5Padding");
c1.init(Cipher.DECRYPT_MODE, key);
byte[] encodedText = Base64.getDecoder().decode(text.getBytes(StandardCharsets.UTF_8));
byte[] encVal = c1.doFinal(encodedText);
System.out.println(new String(encodedText));
return new String(encVal,StandardCharsets.UTF_8);
}
And the error:
Encoded text: aG9sYWNraXNqbWRlaXJncw==
Encoded val: ???D>??|??i9???Fd?\Zz?A?-
Exception in thread "main" java.lang.IllegalArgumentException: Illegal base64 character -3d
at java.util.Base64$Decoder.decode0(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at AESEncryption.desEncrypt(AESEncryption.java:63)
at AESEncryption.main(AESEncryption.java:79)
Thank you very much, and forgive for not providing all the info needed
Your code makes no sense: converting a String to UTF8 and getting back a String makes no sense: a String contains characters. Not bytes.
Encoding a key to base64 doesn't make much sense either. Encoding the plain text to base64 is useless, too.
You need base64 encoding when you have random, binary bytes, and you want to transform them to printable english characters. Only then.
So the process should be:
transform your key to bytes (using String.getBytes(UTF_8)). Unless the String key is in fact a base64-encoded byte array, in which case you need to base64 decode it;
transform the plain text to bytes (using String.getBytes(UTF_8));
encrypt the bytes you got from step 2, using the key obtained from step 1. You obtain completely "random" bytes. These bytes don't represent characters encoded in your platform default charset. So transforming them to a String using new String(bytes) doesn't make any sense, and is a lossy transformation.
Just return the result as a byte array, or if you really want printable characters, base64-encode the bytes, and return the string you obtain from this base64 encoding.
To decrypt, use the reverse process:
Use the same thing as in step 1 above to get the key
take the bytes obtained from step4 above (if you chose to return a byte array), or base64-decode the string, to obtain the original random binary bytes
decrypt the bytes obtained from step 2, using the key obtained from step 1. You get a byte array representing the UTF8-encoded characters of the original plain text.
Use new String(decryptedBytes, UTF_8) to transform this byte array to a String.
I am in a situation where a JSON is encrypted in PHP's openssl_encrypt and needs to be decrypted in JAVA.
$encrypted = "...ENCRYPTED DATA...";
$secretFile = "/path/to/secret/saved/in/text_file";
$secret = base64_decode(file_get_contents($secretFile));
var_dump(strlen($secret)); // prints : int(370)
$iv = substr($encrypted, 0, 16);
$data = substr($encrypted, 16);
$decrypted = openssl_decrypt($data, "aes-256-cbc", $secret, null, $iv);
This $decrypted has correct data which is now decrypted.
Now, the problem is when I try to do same things in Java it doesn't work :(
String path = "/path/to/secret/saved/in/text";
String payload = "...ENCRYPTED DATA...";
StringBuilder output = new StringBuilder();
String iv = payload.substring(0, 16);
byte[] secret = Base64.getDecoder().decode(Files.readAllBytes(Paths.get(path)));
String data = payload.substring(16);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(), 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); // This line throws exception :
cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
Here it is:
Exception in thread "main" java.security.InvalidKeyException: Invalid AES key length: 370 bytes
at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91)
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:591)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:346)
at javax.crypto.Cipher.init(Cipher.java:1394)
at javax.crypto.Cipher.init(Cipher.java:1327)
at com.sample.App.main(App.java:70)
I have already visited similar question like
AES-256 CBC encrypt in php and decrypt in Java or vice-versa
openssl_encrypt 256 CBC raw_data in java
Unable to exchange data encrypted with AES-256 between Java and PHP
and list continues.... but no luck there
btw, this is how encryption is done in PHP
$secretFile = "/path/to/secret/saved/in/text_file";
$secret = base64_decode(file_get_contents($secretFile));
$iv = bin2hex(openssl_random_pseudo_bytes(8));
$enc = openssl_encrypt($plainText, "aes-256-cbc", $secret, false, $iv);
return $iv.$enc;
and yes, I forgot to mention that my JRE is already at UnlimitedJCEPolicy and I can't change PHP code.
I am totally stuck at this point and can't move forward. Please help out.
EDIT#1
byte[] payload = ....;
byte[] iv = ....;
byte[] secret = ....; // Now 370 bits
byte[] data = Base64.getDecoder().decode(payload);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(secret, 0, 32), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv, 0, cipher.getBlockSize());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] output = cipher.doFinal(data);
System.out.println(new String(output).trim());
Above snippet seems to be working with openssl_encrypt
EDIT#2
I am not sure if this is correct, but following is what I have done and encryption-decryption on both side are working fine.
Encrypt in PHP, Decrypt in JAVA use AES/CBC/NoPadding
Encrypt in JAVA, Decrypt in PHP use AES/CBC/PKCS5Padding
I won't provide a complete solution, but there are a few differences you should take care of
Encoding:
String iv = payload.substring(0, 16);
String data = payload.substring(16);
are you sure the IV and data are the same in Java and PHP (The IV is string?)? If the data are encrypted, they should be treated as a byte array, not string. Just REALLY make sure they are THE SAME (print hex/base64 in php and java)
For the IV you at the end call iv.getBytes(), but the locale encoding may/will corrupt your values. The String should be use only when it's really string (text). Don't use string for binaries.
Simply treat data and iv as byte[]
Key generation according to the openssl
AES key must have length of 256 bit for aes-256-cbc used. The thing is - openssl by default doesn't use the provided secret as a key (I believe it can, but I don't know how it is to be specified in PHP).
see OpenSSL EVP_BytesToKey issue in Java
and here is the EVP_BytesToKey implementation: https://olabini.com/blog/tag/evp_bytestokey/
you should generate a 256 bit key usging the EVP_BytesToKey function (it's a key derivation function used by openssl).
Edit:
Maarten (in the comments) is right. The key parameter is the key. Seems the PHP function is accepting parameter of any length which is misleading. According to some articles (e.g. http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-instead-of) the key is trucated or padded to necessary length (so seems 370 bit key is truncated to length of 256 bits).
According to your example, I wrote fully working code for PHP and Java:
AesCipher class: https://gist.github.com/demisang/716250080d77a7f65e66f4e813e5a636
Notes:
-By default algo is AES-128-CBC.
-By default init vector is 16 bytes.
-Encoded result = base64(initVector + aes crypt).
-Encoded/Decoded results present as itself object, it gets more helpful and get possibility to check error, get error message and get init vector value after encode/decode operations.
PHP:
$secretKey = '26kozQaKwRuNJ24t';
$text = 'Some text'
$encrypted = AesCipher::encrypt($secretKey, $text);
$decrypted = AesCipher::decrypt($secretKey, $encrypted);
$encrypted->hasError(); // TRUE if operation failed, FALSE otherwise
$encrypted->getData(); // Encoded/Decoded result
$encrypted->getInitVector(); // Get used (random if encode) init vector
// $decrypted->* has identical methods
JAVA:
String secretKey = "26kozQaKwRuNJ24t";
String text = "Some text";
AesCipher encrypted = AesCipher.encrypt(secretKey, text);
AesCipher decrypted = AesCipher.decrypt(secretKey, encrypted);
encrypted.hasError(); // TRUE if operation failed, FALSE otherwise
encrypted.getData(); // Encoded/Decoded result
encrypted.getInitVector(); // Get used (random if encode) init vector
// decrypted.* has identical methods
public static String encryptByPublicKey(byte[] data, String key)
throws Exception {
byte[] keyBytes = decryptBASE64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return new String(cipher.doFinal(data));
}
I have a public key, like MFWww.........EAAQ==. When I pass the string to that argument, the encrypted message is some unknown characters. Therefore I suspect I should do something on the key before passing it to the function. But I don't how could I make it. So see anyone can help.
Thank you
Never, ever, ever pass arbitrary binary data to the String constructor. You don't have encoded text, you have arbitrary bytes. That's not what the String constructor is for.
Ideally, don't represent the binary data as text at all - but if you have to, do so using base64 or hex, which will encode arbitrary binary data in ASCII.
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.