【问题标题】:Unable to parse as integer in Android无法在 Android 中解析为整数
【发布时间】:2014-01-20 18:28:04
【问题描述】:

我想为一些String 值实现encryptdecrypt 操作。我已正确加密,但我不明白如何decrypt 这个值,例如:

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

当我解密时,我得到NumberFormatException

这是我的简单 Crypto 类

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

    }

这是日志猫信息。

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"}

【问题讨论】:

  • 你的 logcat 说 'java.lang.NumberFormatException: 无法将 '{"' 解析为整数'。这是什么意思?
  • 我已经验证了,你的输入是有效的,你的逻辑也是有效的,详情如下!
  • 仅使用 JSON 数据的“响应”部分。而不是整个 Json 字符串作为字符串

标签: java android encryption aes number-formatting


【解决方案1】:

我假设你是decrypting 整个JSON 字符串,我认为你只需要decrypt

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

所以你应该parse JSON 并从JSON 得到Response string 然后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 stringresponse variable 中。现在你可以decryptresponse string

【讨论】:

  • 以上是我从服务器得到的 JSON 响应字符串,这个字符串我想解密它。
  • 你能建议我怎么做吗?
  • tazeenmulani: 你得到一个 NumberFormatException 因为方法 toByte() 期望输入字符串是十六进制的,但你的例子中的字符串不是。我怀疑 JSON 数据在加密后是 base64 编码的。这样做可能是为了防止空值或其他字符混淆 HTTP 流。在通过解密运行之前尝试对字符串进行 base64 解码。
  • @JeffreyPortouw 我在下面的同一行添加了我的答案,解码了 BASE64 并尝试解密为字节。看来 OP 毕竟对它失去了兴趣
【解决方案2】:

我已经测试了您的课程,并且正如我所见,它可以正常工作。这是我的测试:

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 是因为你的类只解密了十六进制字符串,但这个不是十六进制的。

【讨论】:

  • 我正在使用你的代码行我得到 BadPaddingException 垫块损坏。
  • 并且也无法将“NJ”解析为整数。
  • 我之前说过解析为整数 - 你的类只解密十六进制格式的字符串。 NJGOkF2EvOIpfKG14LHQZrVfj\... 不是十六进制的!
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    十六进制字符串到字节数组的转换请查看[链接]https://stackoverflow.com/a/140861/3131537

    希望能解决你的问题

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

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

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

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

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

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

          提取正确的响应:

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

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

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

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

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

          修复代码:

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

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

          回到您的算法,您的解密方法需要 Hex 形式的加密数据,但您得到的是 Base64 编码的字符串。

          符合您的逻辑预期(我不想更改您的原始基本代码)

          1. 我们必须解码 Base64 编码的字符串 - 有多种风格可供选择,我在此测试中使用了 org.apache.commons.codec.binary.Base64
          2. 将其转换为十六进制
          3. 将其提供给 decrypt 方法

          在代码中这样翻译的步骤序列(在我的测试类主方法中):

          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:‰§ŒÔ³
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-11
            • 1970-01-01
            • 2017-05-06
            • 2017-06-15
            相关资源
            最近更新 更多