Swift使用Security框架RSA私钥加密返回nil问题求助
移动端RSA私钥加密返回nil问题排查
我正在开发一款静态库,功能为接收输入字符串,使用RSA私钥加密后返回(客户端要求移动端采用私钥加密)。参考两篇文章修改适配私钥的代码,但加密结果始终返回nil。
测试用私钥
let privateTestingKey = "-----BEGIN RSA PRIVATE KEY-----MIICXwIBAAKBgQDPJfl0gC95kB3sS0SOfXW45UooiYjT3ZeHRDn/eG+So09x7cXLVbRILxxXfaU+9b5Yw2wETMvuzhP8C5Qd5PQy5lkH5LjcqJjDTvOBuBxNOSY4rmlqdy/skqM4FHjTGdwI2nZiVkjqOFXM+XZ94Ar+pszJifbSPElR1pO4NfT76QIDAQABAoGBAJjtoRdoFyR4yA6NlsRXTRS+ehwpRVGcc2TScrrvL/ejB2DFuFOgJyNvXE4fHWK4y9j+FP2rsJbRnyFhbu0O/VRNPa5Llnejea+5ov/3wxFqiae7pn6bjmiW/xdy0ycLWo90wLX9QqYjKBHomnh15FIajmSuRaUlBaL6DiZt010tAkEA0zLTPiH35meyXim7I7+mMmAN68zGu3cYpqq8i/xlHvXjWrBDV5saxRDsm97ktFqiRpvIoV3n0ZoT+3xjKhGINwJBAPsXM9hWdmWUXmaaAnXZDmKbNltRSZaaz4BktGRUJM0grt7kMndfBgd2JENNzYTfLpOWMIfHXpW9T4pVCjg5TN8CQQDGZf91ZbmYUx+HP5KSUY4R0pQhR/wEzSt2HfwDUPW5cOnEHsMUQBuUtoJfJrMYDfBVfjCqDiogh6pv2/jX4yJfAkEAqwsvQhwEI0Zi2DnpmyX1aq6Y5LQHERT8bVYsnHvFZgbxmNySlEai8MpGAaMqcW0naVpSTOw/PnnriSxM/efquQJBAM/3eRqzBHp/v3bRM+npSgEOaeOmtNiz+oNrJ09mUToyDTkuFOg7J9ojNkeviR4xqs9Hoos8lP3ho1uVcE3/tRQ=-----END RSA PRIVATE KEY-----"
RSA加密代码
import Foundation import Security public class MPEncryption { var publicKey: SecKey! public init(publicKeyString: String) throws { self.publicKey = try makePublicKey(from: publicKeyString) } private func makePublicKey(from keyString: String) throws -> SecKey { let pubKeyData = Data(base64Encoded: sanitize(key: keyString))! let query: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 1024 ] var unmanagedError: Unmanaged<CFError>? guard let pubKeyRef = SecKeyCreateWithData(pubKeyData as CFData, query as CFDictionary, &unmanagedError) else { throw unmanagedError!.takeRetainedValue() as Error } return pubKeyRef } public func encrypt(value: String) throws -> String { let valueData = value.data(using: .utf8)! let bufferSize = SecKeyGetBlockSize(publicKey) - 11 let buffers = makeBuffers(fromData: valueData, bufferSize: bufferSize) var encryptedData = Data() for buffer in buffers { var encryptionError: Unmanaged<CFError>? guard let encryptedBuffer = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, buffer as CFData, &encryptionError) as Data? else { throw encryptionError!.takeRetainedValue() as Error } encryptedData.append(encryptedBuffer) } return encryptedData.base64EncodedString() } private func makeBuffers(fromData data: Data, bufferSize: Int) -> [Data] { guard data.count > bufferSize else { return [data] } var buffers: [Data] = [] for i in 0..<bufferSize { let start = i * bufferSize let lengthOffset = start + bufferSize let length = lengthOffset < data.count ? bufferSize : data.count - start let bufferRange = Range<Data.Index>(NSMakeRange(start, length))! buffers.append(data.subdata(in: bufferRange)) } return buffers } private func sanitize(key: String) -> String { let headerRange = key.range(of: "-----BEGIN RSA PRIVATE KEY-----") let footerRange = key.range(of: "-----END RSA PRIVATE KEY-----") var sanitizedKey = key if let headerRange = headerRange, let footerRange = footerRange { let keyRange = Range<String.Index>(uncheckedBounds: (lower: headerRange.upperBound, upper: footerRange.lowerBound)) sanitizedKey = String(key[keyRange]) } return sanitizedKey .trimmingCharacters(in: .whitespacesAndNewlines) .components(separatedBy: "\n") .joined() } }
排查建议
- 修正变量命名混淆问题:代码中变量名
publicKey实际存储的是私钥,init方法参数publicKeyString也与实际传入的私钥不符,这会导致逻辑混乱。建议将变量名改为privateKey,参数名改为privateKeyString,避免传入错误密钥类型。 - 处理Base64解码失败场景:
Data(base64Encoded: sanitize(key: keyString))!使用强制解包,若私钥清洗后解码失败会直接崩溃,应添加安全判断:guard let privateKeyData = Data(base64Encoded: sanitize(key: keyString)) else { throw NSError(domain: "MPEncryption", code: -1, userInfo: [NSLocalizedDescriptionKey: "私钥Base64解码失败"]) } - 修复分块加密循环逻辑:
makeBuffers方法的循环条件0..<bufferSize错误,会导致循环次数远大于实际需要的分块数。正确逻辑应计算总块数后循环:private func makeBuffers(fromData data: Data, bufferSize: Int) -> [Data] { guard data.count > bufferSize else { return [data] } var buffers: [Data] = [] let totalChunks = (data.count + bufferSize - 1) / bufferSize for i in 0..<totalChunks { let start = i * bufferSize let length = min(bufferSize, data.count - start) let buffer = data.subdata(in: start..<start+length) buffers.append(buffer) } return buffers } - 确认私钥加密的算法合理性:标准RSA体系中,私钥加密本质是签名操作,公钥解密是验证。若服务端用公钥解密,建议改用签名API替代加密API,示例:
// 替换encrypt方法中的加密逻辑 guard let signature = SecKeyCreateSignature(privateKey, .rsaSignatureMessagePKCS1v15SHA256, buffer as CFData, &encryptionError) as Data? else { throw encryptionError!.takeRetainedValue() as Error } encryptedData.append(signature) - 验证密钥加载有效性:通过
SecKeyGetBlockSize(privateKey)检查返回值,1024位RSA的块大小应为128字节,若不符说明密钥加载失败。 - 捕获并打印具体错误信息:在加密逻辑中,当
SecKeyCreateEncryptedData返回nil时,打印错误详情,直接定位问题根源:guard let encryptedBuffer = SecKeyCreateEncryptedData(privateKey, .rsaEncryptionPKCS1, buffer as CFData, &encryptionError) as Data? else { let error = encryptionError!.takeRetainedValue() print("加密错误: \(error.localizedDescription)") throw error as Error }
内容的提问来源于stack exchange,提问作者Bryce Chan
相关产品推荐
相关产品推荐

