Swift中基于字节数组创建RSA公钥失败,求无第三方库解决方案
解决SecKeyCreateWithData创建RSA公钥报错-50的问题
碰到这个SecKeyCreateWithData报错NSOSStatusErrorDomain Code=-50的问题,我太熟悉了!本质就是公钥数据格式不符合Apple Security框架的要求,咱们一步步排查解决:
核心原因:公钥数据格式不对
SecKeyCreateWithData并不接受裸的RSA模(n)+指数(e)字节数组,它要求的是DER编码的PKCS#1或PKCS#8格式的公钥数据。如果你的PublicKeyDataDevQA是直接拼接模和指数得到的,或者格式不对,必然会触发这个错误。
解决方案步骤
1. 确认你的公钥原始形态
分两种情况处理:
- 情况一:有PEM格式公钥
如果你的公钥原本是PEM格式(开头是-----BEGIN RSA PUBLIC KEY-----),需要先去掉头尾标记和换行符,然后Base64解码得到DER格式数据,再传入SecKeyCreateWithData。 - 情况二:只有模和指数的字节数组
这种情况需要手动组装成PKCS#1格式的DER编码数据,下面是封装好的Swift函数:func rsaPublicKeyDataFromModulus(_ modulus: Data, exponent: Data) -> Data? { // PKCS#1 RSAPublicKey ASN.1结构定义 // 先构建基础的ASN.1头部,这里适配1024位RSA公钥 var asn1Header: [UInt8] = [ 0x30, 0x82, 0x01, 0x22, // SEQUENCE标签+长度占位 0x02, 0x82, 0x01, 0x01, // INTEGER(模)的标签+长度 ] // 处理模数据:如果最高位是1,补0x00避免被解析为负数 var modulusData = modulus if (modulusData[0] & 0x80) != 0 { modulusData.insert(0x00, at: 0) } // 处理指数数据(通常是65537,即0x010001) let exponentHeader: [UInt8] = [ 0x02, 0x03, // INTEGER(指数)的标签+长度 ] var exponentData = exponent if (exponentData[0] & 0x80) != 0 { exponentData.insert(0x00, at: 0) } // 拼接所有部分 var derData = Data(asn1Header) derData.append(modulusData) derData.append(exponentHeader) derData.append(exponentData) // 修正SEQUENCE的实际长度 let totalLength = derData.count - 2 derData[1] = UInt8(totalLength >> 16) derData[2] = UInt8(totalLength >> 8) derData[3] = UInt8(totalLength) return derData }
2. 修正公钥创建代码
用上面的函数生成正确的DER数据后,再调用SecKeyCreateWithData,同时注意属性字典的正确性:
// 假设你已经拆分出模和指数的Data let modulusData: Data = ... // 你的RSA模字节数组 let exponentData: Data = ... // 你的RSA指数字节数组 guard let correctPublicKeyData = rsaPublicKeyDataFromModulus(modulusData, exponent: exponentData) else { print("无法生成正确的DER格式公钥") return } // 属性字典:确保KeySize和你的公钥长度一致(1024/2048等) let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits as String: 1024 // 这里要匹配你的公钥实际长度 ] var pubKeyCreateError: Unmanaged<CFError>? if let publicKey = SecKeyCreateWithData(correctPublicKeyData as CFData, attributes as CFDictionary, &pubKeyCreateError) { print("公钥创建成功!") // 接下来可以用SecKeyEncrypt加密密码 let password = "your_password".data(using: .utf8)! var encryptError: Unmanaged<CFError>? if let encryptedData = SecKeyEncrypt(publicKey, .pkcs1, password as CFData, &encryptError) { print("密码加密成功:\(encryptedData as Data)") } else { print("加密失败:\(encryptError?.takeRetainedValue() ?? "")") } } else { if let error = pubKeyCreateError?.takeRetainedValue() { print("SecKeyCreateWithData failed: \(error.localizedDescription)") print("错误详情:\(error)") } }
3. 额外排查点
- 检查
kSecAttrKeySizeInBits的值是否和你的公钥实际长度一致,比如公钥是2048位的,这里要改成2048,否则也会触发错误。 - 打印
correctPublicKeyData的长度:1024位RSA的PKCS#1 DER数据大概是162字节左右,如果长度偏差太大,说明格式组装有误。
内容的提问来源于stack exchange,提问作者Kannan Prasad
相关产品推荐
相关产品推荐

