无法在Android中解析为整数

时间:2014-01-03 06:10:48

标签: java android encryption aes number-formatting

我想对某些encrypt值实施decryptString操作。我已正确加密但我不明白如何decrypt这个值如下:

jsonString Values ={"Response":"NJGOkF2EvOIpfKG14LHQZrVfj\/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4\/\/uxjDwtZ","statusFlag":"true"}

当我解密时,我得到NumberFormatException

这是我简单的加密类

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));
            }

    }

这是log cat信息。

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)

我想要解密这个值。我不知道在哪里需要更改SimpleCrypto class

中的代码
jsonString Values = {"Response":"NJGOkF2EvOIpfKG14LHQZrVfj\/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4\/\/uxjDwtZ","statusFlag":"true"}

7 个答案:

答案 0 :(得分:3)

我假设您decrypting字符串为JSON,我认为您只需要decrypt

此字符串: NJGOkF2EvOIpfKG14LHQZrVfj\/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4\/\/uxjDwtZ

因此,您应该parse JSON并从Response string获取JSON,然后decrypt

  

更新: 您可以像这样解析json字符串:

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();
    }

现在,encrypted中有string response variable。现在,您可以decrypt response string

答案 1 :(得分:1)

我已经测试了你的课程,它正如我所见的那样工作。这是我的测试:

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);
} 

并输出:

B7498FF642FA8B81289AE8E59E19F081A27B766BE3290617CC15F857BF055DA2668BF81181E26AE2F790968DF39CC070
Some string that i want to encrypt and decrypt

您正在获取NumberFormatException,因为您的类仅解密带有六角形的字符串,但这个字符串不会被删除。

答案 2 :(得分:1)

您尝试将整数字符串'NJ'解析为十六进制数字。但是HEX只有0-9和A-F符号。将您的收入字符串更改为仅HEX符号。

答案 3 :(得分:1)

我认为result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();会给你错误,因为你的六角形字符串可能包含字符文字,所以Integer.valueOf()函数会给你NumberFormatException

对于hexstring到byte的数组转换,请检查[link] https://stackoverflow.com/a/140861/3131537

希望能解决您的问题

答案 4 :(得分:0)

您正在尝试解析整个字符串,其中不仅包含数字,还包含文本(String)。请检查您的代码,然后将其设为问题

答案 5 :(得分:0)

您的解决方案有效,您获得的数据的解释与实际发生的情况不一致。

您的JSON响应不是加密的字节数组,而是编码的字符串。要通过网络流式传输字节数组(或位或任何二进制数据),通常不会以其原始格式发送。相反,您希望编码您的原始数据为字符

由于您的JSON响应看起来像是字符流而不是字节的原始格式,我可以做的第一个假设是使用最常见的二进制到字符串编码之一的编码数据 - Base64

以下字符串(响应)是有效的Base64 编码字符串,而您的decrypt方法需要 Hex 编码的字符流。

  

NJGOkF2EvOIpfKG14LHQZrVfj / OEJvopi + OKU + q5G2ynDbVUnIckfMLGCCsxcY9 + BmVg + KJXF1ls \ nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4 // uxjDwtZ

提取正确的答案:

由于JSON'允许'转义前斜杠和其他转义序列,因此需要稍微格式化Base64响应。

我删除了前斜杠的转义符,并'换行'换行符的'\'(\ n)。生成的String看起来像(注意\ n):

NJGOkF2EvOIpfKG14LHQZrVfj/OEJvopi+OKU+q5G2ynDbVUnIckfMLGCCsxcY9+BmVg+KJXF1ls\\nGf2rWg73iyowyq6THyDfBS8uZnSp9PfS3bJCFb6YWX4//uxjDwtZ

这是一个有效的Base64字符串,您可以对其进行测试here(通过按Enter键将换行符替换为\ n,并将其余文本带到新行。)

enter image description here

请注意,它会下载一个二进制文件作为结果 - 这证明解码后的值实际上是一个有效的二进制原始数据。

修复代码:

NumberFormatException可以看出,你的decrypt方法期待一个十六进制编码的字符流,但它没有得到。

根据您的代码,encrypt函数将返回String的Hex编码值。这也是有效的,因为Hex也是可读形式的二进制值的表示。但是,您可能需要在集成中进行级别设置以与编码方案保持一致。

回到您的算法,您的解密方法希望加密数据采用十六进制形式,但您获得的是 Base64 编码的字符串。

与您的逻辑预期对齐(我不想对原始基本代码进行更改)

  1. 我们必须解码Base64 编码的字符串 - 各种风格都可用,我使用org.apache.commons.codec.binary.Base64进行此测试。
  2. 将其转换为十六进制
  3. 将其提供给解密方法
  4. 在代码中翻译的步骤序列(在我的测试类主方法中):

    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);
    

    关于加密方案的要点:

    您的AES加密方案使用默认AES方案(Cipher.getInstance("AES");),该方案在SunJCE实施中转换为Cipher.getInstance("AES/ECB/PKCS5Padding");

    当我使用随机密钥abc

    运行时
    javax.crypto.BadPaddingException: Given final block not properly padded
    

    这当然是错误密钥的 方案 ,因为我没有用于加密/解密数据的密钥。

    您可以使用正确的密钥和上述更改来测试此方案,它应该适用于您当前的加密方案。

    我的测试用例:

    作为一个测试用例,我通过用

    替换你的Cipher.getInstance("AES")解密方法来禁止填充限制
    Cipher.getInstance("AES/ECB/NoPadding");
    

    我收到了 无异常 的不可读字符集合,这是可以理解的垃圾值 - 原因,我再次使用了一个与你想要的不一致的随机密钥使用。

    ;l:z«1†ŠåÎàÏÙQPÞ—?ñGv’€ò;PöøïÇE1:‰§ŒÔ³
    

答案 6 :(得分:0)

您正在使用JSON数据作为字符串数据。 你只需要选择像这样的JSON的“响应”部分值

JSONObject jO= new JSONObject(value);
String response = jO.getString("Response");