Swift与Java跨平台加解密适配:BadPadding错误排查及算法选型
我之前在做iOS和Java跨平台加密对接时,正好碰到过和你一模一样的SwiftyRSA PKCS1填充导致Java端BadPadding错误的问题,折腾了好一阵才找到完美的适配方案,分享给你:
问题根源
SwiftyRSA里的PKCS1填充,其实对应Java标准加密库中的**RSA/ECB/PKCS1Padding**算法组合。之所以报错,大概率是Java端没有明确指定完整的算法模式(只写了RSA而省略了ECB/PKCS1Padding),或者误用了其他填充方式(比如OAEP),导致两端算法不匹配。
Swift端加密适配代码
SwiftyRSA默认的PKCS1填充就是和Java RSA/ECB/PKCS1Padding兼容的,只要明确指定填充方式即可,不需要额外设置Mode(SwiftyRSA底层已经默认用了对应ECB的实现):
import SwiftyRSA /// 用PKCS1填充的RSA公钥加密字符串(兼容Java端RSA/ECB/PKCS1Padding解密) func rsaEncrypt(plainText: String, publicKeyPEM: String) throws -> String { // 加载PEM格式公钥 let publicKey = try PublicKey(pemEncoded: publicKeyPEM) // 将明文转为SwiftyRSA的ClearMessage(UTF-8编码) let clearMessage = try ClearMessage(string: plainText, using: .utf8) // 明确指定PKCS1填充(对应Java的RSA/ECB/PKCS1Padding) let encryptedMessage = try clearMessage.encrypted(with: publicKey, padding: .PKCS1) // 转Base64字符串传输(避免二进制数据乱码) return encryptedMessage.base64String }
Java端解密适配代码
Java端必须明确指定完整的算法字符串RSA/ECB/PKCS1Padding,同时要注意私钥的格式兼容(SwiftyRSA常用PKCS8格式的PEM私钥):
import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; public class RSACrossPlatformDecoder { /** * 解密SwiftyRSA用PKCS1填充加密的字符串 * @param encryptedBase64 iOS端加密后传过来的Base64字符串 * @param privateKeyPEM PKCS8格式的PEM私钥(和iOS端公钥配对) * @return 明文 * @throws Exception 解密异常 */ public static String rsaDecrypt(String encryptedBase64, String privateKeyPEM) throws Exception { // 预处理PEM私钥:去掉头尾标记和空白字符 String cleanPrivateKey = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s+", ""); // 解码Base64得到私钥字节数组 byte[] privateKeyBytes = Base64.decodeBase64(cleanPrivateKey); // 生成PKCS8格式的私钥对象 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); // 关键:必须指定完整算法,和SwiftyRSA的PKCS1填充严格对应 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); // 解码加密后的Base64字符串,执行解密 byte[] encryptedBytes = Base64.decodeBase64(encryptedBase64); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); // 用UTF-8编码转成明文(和iOS端编码一致) return new String(decryptedBytes, "UTF-8"); } }
关键注意事项&排查Tips
- 密钥对必须配对:确保iOS加密用的公钥和Java解密用的私钥是同一套,推荐用OpenSSL生成标准密钥对:
# 生成2048位RSA私钥(PKCS8格式) openssl genrsa -out private_key.pem 2048 openssl pkcs8 -topk8 -inform PEM -in private_key.pem -out private_key_pkcs8.pem -nocrypt # 生成对应公钥 openssl rsa -in private_key.pem -pubout -out public_key.pem - 编码统一:两端都必须用UTF-8编码处理字符串,不能一端用UTF-8另一端用GBK或UTF-16。
- Base64一致性:iOS输出的Base64字符串要和Java接收的完全一致,不能有换行、空格或额外字符。
- 私钥格式兼容:如果你的私钥是PKCS1格式(开头是
-----BEGIN RSA PRIVATE KEY-----),Java端要改用RSAPrivateKeySpec来加载,而不是PKCS8EncodedKeySpec。
内容的提问来源于stack exchange,提问作者Pyae Phyoe Shein
相关产品推荐
相关产品推荐

