Reputation: 592
I want to implement encrypt
and decrypt
operation for some String
values. I have encrypted properly but I don't understand how to decrypt
this value like:
jsonString Values ={"Response":"NJGOkF2EvOIpfKG14LHQZrVfj\/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4\/\/uxjDwtZ","statusFlag":"true"}
When I decrypt, I am getting NumberFormatException
.
Here is my simple Crypto class
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class SimpleCrypto {
public static String encrypt(String seed, String cleartext) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue(); //2 * i, 2 * i + 2
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
}
This is log cat infomation .
01-03 11:30:51.154: W/System.err(437): java.lang.NumberFormatException: unable to parse '{"' as integer
01-03 11:30:51.164: W/System.err(437): at java.lang.Integer.parse(Integer.java:383)
01-03 11:30:51.164: W/System.err(437): at java.lang.Integer.parseInt(Integer.java:372)
01-03 11:30:51.164: W/System.err(437): at java.lang.Integer.valueOf(Integer.java:528)
01-03 11:30:51.164: W/System.err(437): at com.json_to_server.SimpleCrypto.toByte(SimpleCrypto.java:63)
01-03 11:30:51.164: W/System.err(437): at com.json_to_server.SimpleCrypto.decrypt(SimpleCrypto.java:20)
01-03 11:30:51.164: W/System.err(437): at com.json_to_server.EncryptDecrypt_Demo.POST(EncryptDecrypt_Demo.java:202)
01-03 11:30:51.174: W/System.err(437): at com.json_to_server.EncryptDecrypt_Demo$HttpAsyncTask.doInBackground(EncryptDecrypt_Demo.java:267)
01-03 11:30:51.174: W/System.err(437): at com.json_to_server.EncryptDecrypt_Demo$HttpAsyncTask.doInBackground(EncryptDecrypt_Demo.java:1)
01-03 11:30:51.174: W/System.err(437): at android.os.AsyncTask$2.call(AsyncTask.java:185)
01-03 11:30:51.174: W/System.err(437): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
01-03 11:30:51.174: W/System.err(437): at java.util.concurrent.FutureTask.run(FutureTask.java:138)
01-03 11:30:51.174: W/System.err(437): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
01-03 11:30:51.174: W/System.err(437): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
01-03 11:30:51.174: W/System.err(437): at java.lang.Thread.run(Thread.java:1019)
And i want to decrypt this value. I don't know where i have to change the code in my SimpleCrypto class
jsonString Values = {"Response":"NJGOkF2EvOIpfKG14LHQZrVfj\/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4\/\/uxjDwtZ","statusFlag":"true"}
Upvotes: 2
Views: 1092
Reputation: 8617
Your solution works, the interpretation of the data you are getting is misaligned with what is actually happening.
Your JSON response is not an encrypted byte array but an encoded String. To stream across an array of Bytes (or bits or any binary data for that matter) through a network, it is not generally sent in its raw format. Rather, you want to encode your raw data into characters.
Since your JSON response looks like a stream of characters and not a raw format of bytes, the first assumption I can make is it's an encoded data using one of the most common binary to String encoding - Base64.
The below string (response) is a valid Base64 encoded String, while your decrypt method is expecting the Hex encoded stream of characters.
NJGOkF2EvOIpfKG14LHQZrVfj/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4//uxjDwtZ
Since JSON 'allows' you to escape front slashes and other escape sequences, your Base64 response needs to be slightly formatted.
I remove the escapes for front slashes and 'escape' the '\' for the line feed (\n). The resulting String looks like (notice \n):
NJGOkF2EvOIpfKG14LHQZrVfj/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4//uxjDwtZ
This is a valid Base64 String, you can test it here (replace \n with a line feed by pressing enter and bringing the rest of the text to the new line).
Notice it downloads a binary file as a result - which proves the the decoded value is in fact a valid binary raw data.
As it's evident from NumberFormatException
, your decrypt
method is expecting a Hex encoded stream of characters which it does not get.
As per your code, the encrypt function would return the Hex encoded value of the String. This is valid as well since Hex is also a representation of binary values in a readable form. However, you might need to level set within your integration to be consistent with the encoding scheme.
Coming back to your algorithm, your decrypt methods expect the encrypted data in Hex form but what you get is a Base64 encoded String.
Aligned to what your logic expects (I didn't want to make changes to your original base code)
org.apache.commons.codec.binary.Base64
for this test.The sequences of steps translated like this in the code (within my test class main method):
String encoded = "NJGOkF2EvOIpfKG14LHQZrVfj/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4//uxjDwtZ";
String key = "abc";
String decoded = toHex(Base64.decodeBase64(encoded));
System.out.println(decoded);
String decrypted = decrypt(key, decoded);
System.out.println(decrypted);
Your AES encryption scheme uses a default AES scheme (Cipher.getInstance("AES");
) which translates to Cipher.getInstance("AES/ECB/PKCS5Padding");
in SunJCE implementation.
When I run this with a random key abc
javax.crypto.BadPaddingException: Given final block not properly padded
This of course is the scenario of a wrong key as I do not have the key which you would use to encrypt/decrypt your data.
You can test this scenario with the right key and the changes mentioned above, it should work with your current encryption scheme.
As a test case, I disallowed the restraint of padding by replacing your Cipher.getInstance("AES")
in decrypt method with
Cipher.getInstance("AES/ECB/NoPadding");
I get a collection of unreadable characters with no exception, which are understandably junk values - reason, again I used a random key which does not align to what you intend to use.
;l:z«1†ŠåÎàÏÙQPÞ—?ñGv’€ò;PöøïÇE1:‰§ŒÔ³
Upvotes: 0
Reputation: 1036
You are using JSON data as string data. you need to pick only the "response" part value of the JSON something like this
JSONObject jO= new JSONObject(value);
String response = jO.getString("Response");
Upvotes: 0
Reputation: 3256
I think result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
gives you error because your hexstring may contain character literal so Integer.valueOf() function gives you NumberFormatException
for hexstring to byte array conversion please check [link] https://stackoverflow.com/a/140861/3131537
hope that solves your problem
Upvotes: 1
Reputation: 4857
You trying parse to Integer string 'NJ' as HEX-digits. But HEX is only 0-9 and A-F symbols. Change your income string to only HEX symbols.
Upvotes: 1
Reputation: 3757
I've tested your class and it's working as i see. Here is my test:
public static void main(String[] args) throws Exception {
String message = "Some string that i want to encrypt and decrypt";
String key = "123";
String encrypted = SimpleCrypto.encrypt(key, message);
p(encrypted);
String decrypted = SimpleCrypto.decrypt(key, encrypted);
p(decrypted);
}
private static void p(String message) {
System.out.println(message);
}
and output:
B7498FF642FA8B81289AE8E59E19F081A27B766BE3290617CC15F857BF055DA2668BF81181E26AE2F790968DF39CC070
Some string that i want to encrypt and decrypt
You're getting NumberFormatException because your class decrypts only hexed strings, but this one is not hexed.
Upvotes: 1
Reputation: 9827
I assume you are decrypting
the whole JSON
string and I think you only need to decrypt
this string :
NJGOkF2EvOIpfKG14LHQZrVfj\/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4\/\/uxjDwtZ
So you should parse
the JSON
and get Response string
from JSON
and then decrypt
it.
UPDATE : You can parse you json string like this :
String value = "YOUR_JSON_STRING";
try {
JSONObject mJsonObject = new JSONObject(value);
String response = mJsonObject.getString("Response");
//Decrypt response string
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Now you have your encrypted
string
in response variable
. Now you can decrypt
response string
.
Upvotes: 3
Reputation: 989
You are trying to parse the whole string which containts not only numbers but also text (String). Please review your code and then make this a question
Upvotes: 0