Ray*_*Ray 9 java encryption android rsa public-key-encryption
我的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;
}
Run Code Online (Sandbox Code Playgroud)
后端团队提供了以下示例代码,但它适用于桌面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);
Run Code Online (Sandbox Code Playgroud)
我比较了每一步的字节数组值.桌面密码和android密码获得完全相同的输入.但是,Android代码cipher.doFinal的结果无法被后端解密.如果我将桌面结果放到REST调用体中它们工作正常,那么它不是由REST调用引起的.
我还尝试在Android上创建一个公钥/私钥对,并使用生成的公钥加密而不是使用后端的公钥,并使用私钥解密,它可以工作.所以密码也在工作,只是某种程度上后端期待不同的东西
最后团队成员破解了这一点.原因是因为Android OS使用Bouncy城堡,后端使用Sun作为提供者,这导致后端抛出BadPaddingException.要使其工作,需要在Android上以这种方式初始化密码:
mCipher.init(Cipher.ENCRYPT_MODE, key, new
OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1,
PSource.PSpecified.DEFAULT));
Run Code Online (Sandbox Code Playgroud)
请查看此帖子中的更多详细信息:http: //bouncy-castle.1462172.n4.nabble.com/Problems-with-OAEP-SHA-256-hash-crypto-td1466852.html