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