0

我加密/解密如下消息:加密字符串 -> base64 编码字节 -> 序列化字符串 -> 反序列化字符串 -> 解码 b64 -> 解密字节。

加密看起来像这样:

PublicKey pubKey = readPublicKey();
Cipher cipher;
cipher = Cipher.getInstance(CRYPTO_ALG);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData;
cipherData = cipher.doFinal(message.getBytes());
return cipherData;

解密是这样完成的:

PrivateKey pk = readPrivateKey();
Cipher cipher = Cipher.getInstance(CRYPTO_ALG);
cipher.init(Cipher.DECRYPT_MODE, pk);

return new String(cipher.doFinal(data));

密钥是这样读取的:

ObjectInputStream oin =
   new ObjectInputStream(new BufferedInputStream(is));
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();

RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(keySpec);

return privKey;

我在这里省略了 b64 的东西,但我已经验证问题不会影响该代码。

现在发生的事情是我实际上得到了正确的答案,但它前面带有二进制乱码。如果我加密“TESTDATA”,我将得到 TESTDATA。该代码在纯 Java 中运行良好,但在 Android 中失败。有谁知道如何解决这一问题?

编辑:使用 RSA/NONE/NoPadding 加密/解密似乎没有帮助。我还在普通的 JRE 中使用 org.bouncycastle。

4

1 回答 1

1

根据我的经验,默认值是 Java 加密中难以发现的错误的巨大且永无止境的来源。他们可以咬任何人,但他们捕食初学者。初学者最有可能选择默认值,因为就其本质而言,他们会感到困惑并寻求简化。而且它们很难被发现,实际上几乎是看不见的,因为它们存在。当你看它时,String.getBytes()它看起来完全无辜。为什么初学者会怀疑new String(s.getBytes())不等于?最糟糕的是,测试似乎表明这是真的。只有当您将from传输到具有不同平台默认字符集的另一个平台时,您才会注意到该错误。 sbyte[]s.getBytes()

永远不要用String.getBytes(),永远用String.getBytes(Charset)。永远不要使用String(byte[])构造函数,总是使用String(byte [], Charset)构造函数。您始终可以使用 UTF-8 字符集 ( Charset.forName("UTF-8"))。我专门使用它。

同样,始终在工厂方法中指定所有三个组件算法/模式/填充。Cipher.getInstance(String)

于 2013-01-10T01:20:58.257 回答