iOS Swift RSA加密后如何解密?及与Android加密一致性验证
嘿,我帮你分析下问题所在,以及怎么调整代码让iOS和Android的加解密流程对齐~
问题核心:填充方式不匹配
你iOS代码里用的是PKCS1填充,但Android端用的是OAEP-SHA256填充,这两种填充规则完全不同,导致两边加密的结果无法互相解密,这是最主要的问题。
第一步:修改iOS加密代码,对齐Android的填充规则
从iOS 10开始,系统提供了更灵活的加密API,我们可以直接指定和Android一致的RSA-OAEP-SHA256算法,替换原来的PKCS1填充逻辑。修改后的加密函数如下:
static func encrypt(string: String, publicKey: SecKey) -> String? { // 把要加密的字符串转成UTF-8数据,和Android的编码一致 guard let plainData = string.data(using: .utf8) else { print("字符串转UTF-8失败") return nil } // 指定和Android完全匹配的加密算法:RSA-OAEP-SHA256 let encryptionAlgorithm = SecKeyAlgorithm.rsaEncryptionOAEPSHA256 // 先验证公钥是否支持该算法 guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, encryptionAlgorithm) else { print("当前公钥不支持RSA-OAEP-SHA256加密") return nil } var encryptionError: Unmanaged<CFError>? // 使用新API进行加密,自动处理OAEP填充和SHA256哈希 guard let encryptedData = SecKeyCreateEncryptedData( publicKey, encryptionAlgorithm, plainData as CFData, &encryptionError ) as Data? else { print("加密失败:\(encryptionError?.takeRetainedValue().localizedDescription ?? "未知错误")") return nil } // 转成Base64字符串,和Android的编码格式一致 return encryptedData.base64EncodedString() }
另外,你的公钥解析代码基本没问题,但可以去掉kSecReturnPersistentRef : kCFBooleanTrue这个属性——你只是临时创建公钥对象,不需要持久化引用,简化后的attributes可以写成:
var attributes: CFDictionary { return [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits: 2048 ] as CFDictionary }
第二步:iOS端解密的实现(如果需要)
如果要在iOS端解密Android加密的内容,或者解密自己加密的结果,需要用对应的私钥,并且同样使用OAEP-SHA256算法,代码示例:
static func decrypt(encryptedString: String, privateKey: SecKey) -> String? { // 把Base64字符串转成加密数据 guard let encryptedData = Data(base64Encoded: encryptedString) else { print("Base64解码失败") return nil } let decryptionAlgorithm = SecKeyAlgorithm.rsaEncryptionOAEPSHA256 guard SecKeyIsAlgorithmSupported(privateKey, .decrypt, decryptionAlgorithm) else { print("当前私钥不支持RSA-OAEP-SHA256解密") return nil } var decryptionError: Unmanaged<CFError>? guard let decryptedData = SecKeyCreateDecryptedData( privateKey, decryptionAlgorithm, encryptedData as CFData, &decryptionError ) as Data? else { print("解密失败:\(decryptionError?.takeRetainedValue().localizedDescription ?? "未知错误")") return nil } // 把解密后的二进制转成UTF-8字符串 return String(data: decryptedData, encoding: .utf8) }
第三步:验证加密流程的一致性
现在调整后,两边的加密流程已经对齐了,确认以下几点:
- 填充规则:iOS用
rsaEncryptionOAEPSHA256,对应Android的RSA/NONE/OAEPWITHSHA-256ANDMGF1PADDING,完全匹配 - 密钥长度:都是2048位,没问题
- 字符编码:两边都用UTF-8编码原始字符串
- Base64编码:iOS的
base64EncodedString()是标准无换行格式,和Android API>=O的Base64.getEncoder()一致;如果Android低版本用的是Base64.DEFAULT(会带换行),建议让Android改成Base64.NO_WRAP,或者iOS解码时先去掉换行符
另外还要注意:确保iOS使用的公钥和Android从X.509证书中取出的公钥是同一对密钥的公钥,否则也会导致加解密失败。
内容的提问来源于stack exchange,提问作者Shubham1212
相关产品推荐
相关产品推荐

