Swift中使用RSA公钥无法正确加密数据的问题求助
我用OpenSSL生成了AES256、2048位的RSA公私钥对,服务器端用OpenSSL加解密完全正常,但在Swift里始终无法成功加密数据。尝试多种方法后,数据看似加密完成,但服务器解密时持续报错:
rsa routines:rsa_ossl_private_decrypt:data greater than mod len:crypto\rsa\rsa_ossl.c:407
以下是我的测试代码(忽略强制解包):
1. 从公钥创建SecKey
private func createSecKey() -> SecKey { // Remove headers and footers from the PEM, leaving us with DER encoded data split by new lines [ "-----BEGIN RSA PUBLIC KEY-----", "-----END RSA PUBLIC KEY-----", "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----" ].forEach { publicKey = publicKey.replacingOccurrences(of: $0, with: "") } // Construct DER data from the remaining PEM data let der = Data(base64Encoded: publicKey, options: .ignoreUnknownCharacters)! let attributes: [String: Any] = [ String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeyClass): kSecAttrKeyClassPublic, String(kSecAttrKeySizeInBits): der.count * 8 ] let key = SecKeyCreateWithData(der as CFData, attributes as CFDictionary, nil)! return key }
2. 加密数据
private func encryptMessageData(secKey: SecKey, message: String) { print(aesKeyPair) // An example message to encrypt let messageData = message.data(using: .utf8)! // Perform the actual encryption let encryptedMessage = SecKeyCreateEncryptedData(secKey, .rsaEncryptionOAEPSHA256, messageData as CFData, nil)! as Data print("=====Encrypted Message Below=====") print(encryptedMessage.map { String(format: "%02x", $0) }.joined()) self.encryptedAESKey.text = cipherText.map { String(format: "%02x", $0) }.joined() }
我尝试把加密结果编码为Base64后再解密:
let base64Data = encryptedMessage.base64EncodedData(options: .endLineWithLineFeed)
服务器端执行解密命令:
openssl pkeyutl -decrypt -inkey tvde_private.pem -in message.decoded > message.txt -pkeyopt rsa_padding_mode:oaep
此时报错:
Public Key operation error
501A0000:error:02000079:rsa routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error:crypto\rsa\rsa_oaep.c:314:
我怀疑问题出在加密阶段的算法选择:
let encryptedMessage = SecKeyCreateEncryptedData(secKey, .rsaEncryptionOAEPSHA256, messageData as CFData, nil)! as Data
试过.rsaEncryptionOAEPSHA256和.rsaEncryptionOAEPSHA256AESGCM,但对SecKeyAlgorithm里的算法不太了解,我的密钥是AES256、2048位RSA生成的,求建议。
1. 修正公钥解析错误
你的createSecKey方法中,kSecAttrKeySizeInBits设置错误:DER编码的公钥包含ASN.1结构,不能用der.count * 8计算密钥长度,直接指定2048位即可(和你生成的密钥匹配):
let attributes: [String: Any] = [ String(kSecAttrKeyType): kSecAttrKeyTypeRSA, String(kSecAttrKeyClass): kSecAttrKeyClassPublic, String(kSecAttrKeySizeInBits): 2048 // 直接匹配密钥长度 ]
另外,优先使用PKCS#8格式的公钥(-----BEGIN PUBLIC KEY-----开头),iOS对这种格式支持更稳定。如果你的公钥是PKCS#1格式(-----BEGIN RSA PUBLIC KEY-----),可以用OpenSSL转换:
openssl rsa -in public.pem -pubout -outform PEM -out public_pkcs8.pem
2. 对齐iOS与OpenSSL的OAEP参数
iOS的SecKeyCreateEncryptedData默认用MGF1-SHA256,但OpenSSL默认的OAEP参数是MGF1-SHA1,这是解密报错的核心原因。需要手动指定参数让两端对齐:
// 明确指定OAEP的哈希和MGF1算法 let parameters: [String: Any] = [ kSecKeyAlgorithmOAEPSHA256 as String: [ kSecKeyOAEPHashAttribute: kSecDigestSHA256, kSecKeyOAEPmgfAttribute: kSecKeyOAEPmgf1SHA256 ] ] guard let encryptedMessage = SecKeyCreateEncryptedData(secKey, .rsaEncryptionOAEPSHA256, messageData as CFData, parameters as CFDictionary) as Data? else { // 处理加密失败逻辑 return }
服务器端解密时,必须指定相同的哈希和MGF1算法:
openssl pkeyutl -decrypt -inkey tvde_private.pem -in message.decoded > message.txt -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256
3. 规范数据编码传输
加密后的二进制数据,推荐用Base64编码后传给服务器(避免十六进制转换可能的错误):
let encryptedBase64 = encryptedMessage.base64EncodedString() // 将encryptedBase64传给服务器
服务器读取Base64文件后直接解密即可,无需额外转码。
4. 遵守RSA加密长度限制
2048位RSA用OAEP-SHA256加密时,最大明文长度为2048/8 - 2*256/8 - 2 = 190字节,超过会触发data greater than mod len错误。这时候应该用你提到的AES256配合RSA:
- 生成随机AES256密钥
- 用RSA加密这个AES密钥
- 用AES加密明文数据
- 将加密后的AES密钥+AES密文一起传给服务器,服务器先解密AES密钥,再解密明文
内容的提问来源于stack exchange,提问作者Ryan H

