使用RSA的解密结果在普通Java和Android中有所不同

时间:2013-01-08 11:09:58

标签: java android rsa pki

我加密/解密如下消息: 加密字符串 - > 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。

1 个答案:

答案 0 :(得分:1)

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

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

同样,请始终在Cipher.getInstance(String)工厂方法中指定所有三个组件 algorithm / mode / padding