【发布时间】:2017-10-02 19:31:05
【问题描述】:
我的 Android 应用实现了 RSA 加密,但是后端无法解密应用生成的令牌。这是代码,在调用之前公钥的开头和结尾行已被删除,可能是什么问题?
String encryptedToken = Base64.encodeToString(encrypt(publicKey, "4111111111111111"), Base64.NO_WRAP);
public static byte[] encrypt(String publicKey, String data) {
if (TextUtils.isEmpty(publicKey) || TextUtils.isEmpty(data)) {
return null;
}
try {
// Decode the modified public key into a byte[]
byte[] publicKeyByteArray = Base64.decode(publicKey.getBytes("UTF-8"),Base64.NO_WRAP);
Cipher mCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyByteArray);
Key key = keyFactory.generatePublic(x509KeySpec);
mCipher.init(Cipher.ENCRYPT_MODE, key);
return mCipher.doFinal(data.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e) {
Log.e("RSAKEY", e.getMessage());
}
catch (NoSuchPaddingException e) {
Log.e("RSAKEY", e.getMessage());
} catch (NoSuchAlgorithmException e) {
Log.e("RSAKEY", e.getMessage());
} catch (InvalidKeyException e) {
Log.e("RSAKEY", e.getMessage());
} catch (InvalidKeySpecException e) {
Log.e("RSAKEY", e.getMessage());
} catch (IllegalBlockSizeException e) {
Log.e("RSAKEY", e.getMessage());
} catch (BadPaddingException e) {
Log.e("RSAKEY", e.getMessage());
}
return null;
}
后端团队提供了以下示例代码,但它适用于桌面 java。 Android 库没有 Base64.getEncoder 方法。它与我写的非常相似,但我的只是不起作用。
// Decode the modified public key into a byte[]
byte[] publicKeyByteArray = Base64.getDecoder().decode(publicKey.getBytes(StandardCharsets.UTF_8));
// Create a PublicKey from the byte array
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByteArray);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
// Get an instance of the Cipher and perform the encryption
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(ccNum.getBytes(StandardCharsets.UTF_8));
// Get the encrypted value as a Base64-encoded String
String encodeToStr = Base64.getEncoder().encodeToString(cipherText);
// Print out the encoded, encrypted string
System.out.println("Encrypted and Encoded String: " + encodeToStr);
我在每一步都比较了字节数组的值。桌面密码和安卓密码得到完全相同的输入。然而,Android 代码 cipher.doFinal 的结果无法被后端解密。如果我将桌面结果放到 REST 调用主体中,它们可以正常工作,所以这不是由 REST 调用引起的。
我还尝试在 Android 上创建一个公钥/私钥对,并使用生成的公钥进行加密,而不是使用我们后端的公钥,然后使用私钥解密,它就可以工作了。所以密码也在工作,只是后端期待一些不同的东西
【问题讨论】:
-
有什么问题?也许如果你显示解密代码有人可以回答这个问题。
-
不幸的是我无法访问后端代码,它是一个第 3 方接口。它返回 http 400 错误,ERROR:{"status":400,"error":"DecryptionFailure","message":"Could Not Decrypt Payload. Verify 'Public Key' and 'Algorithm'","timeStamp":"2017 -10-02T19:22:29.785+0000","trace":null,"type":null,"messages":{"DecryptionFailure":"无法解密有效负载。验证“公钥”和“算法”"} }
-
那就这样吧。检查钥匙。检查算法。检查填充物。检查您是否应该发送 base64。您的代码似乎是正确的。
-
为什么选择“RSA/ECB/OAEPWithSHA-256AndMGF1Padding”?
-
这是必需的。我一直在尝试所有 Base64 标志,但没有一个有效。 Base64.NO_WRAP 是唯一一个后端不抱怨错误的base64格式,但仍然无法解码。
标签: java android encryption rsa public-key-encryption