You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:32:20