iOS:CryptoKit SecureEnclave私钥转SecKey报OSStatus -50错误如何解决
错误原因
- 安全隔区生成的P256私钥受硬件保护,明文密钥永远不会离开安全隔区。你调用
dataRepresentation获取到的只是系统用来定位安全隔区内密钥的引用标记,不是SecKeyCreateWithData要求的标准x963格式私钥材料,格式不匹配导致解析失败,返回-50参数错误。 - 普通非安全隔区的P256私钥明文保存在App内存中,
x963Representation返回的是符合要求的标准密钥材料,所以可以正常转换。
修复方案
场景1:仅需要获取对应SecKey实例
不需要手动转换,CryptoKit已经提供了原生的secKey属性,直接调用即可:
let secKey = privateKey.secKey
拿到的SecKey可直接用于后续加密、签名、KeyChain存储等操作。
场景2:需要持久化存储私钥供后续使用
不需要转成SecKey再存,直接把私钥的dataRepresentation作为普通数据存入KeyChain即可,读取后可直接恢复私钥实例:
// 存储私钥引用到KeyChain let saveQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "p256_signing_private_key", kSecValueData as String: privateKey.dataRepresentation, kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly ] // 清除旧数据(可选,避免重复存储报错) SecItemDelete(saveQuery as CFDictionary) // 执行存储 let saveStatus = SecItemAdd(saveQuery as CFDictionary, nil) guard saveStatus == errSecSuccess else { // 处理存储错误 throw NSError(domain: NSOSStatusErrorDomain, code: Int(saveStatus)) } // 读取并恢复私钥 let getQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "p256_signing_private_key", kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne ] var result: AnyObject? let getStatus = SecItemCopyMatching(getQuery as CFDictionary, &result) guard getStatus == errSecSuccess, let keyData = result as? Data else { // 处理读取错误 throw NSError(domain: NSOSStatusErrorDomain, code: Int(getStatus)) } // 直接恢复安全隔区私钥实例 let restoredPrivateKey = try SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: keyData)
内容的提问来源于stack exchange,提问作者Seifer Almasy
相关产品推荐
相关产品推荐

