SecKeyIsAlgorithmSupported报EXC_BAD_ACCESS(code=257)问题求助
解决SecKeyIsAlgorithmSupported调用时的EXC_BAD_ACCESS崩溃问题
崩溃根本原因
你遇到的崩溃完全是类型强转错误导致的:
- 新的
getquery使用了kSecClassGenericPassword(用于存储账号密码类数据),且指定了kSecReturnAttributes,所以SecItemCopyMatching返回的是属性字典数组(因为设置了kSecMatchLimitAll),并非SecKey对象。 - 你直接用
let key = item as! SecKey强制转换,会触发内存访问错误,导致EXC_BAD_ACCESS。
另外,kSecClassGenericPassword本就不是存储加密密钥的正确类型,你之前的旧query(kSecClassKey)才是符合密钥存储逻辑的写法,iPhone13 Pro Max的问题应该是旧query参数缺失,而非换类型就能解决。
解决方案
方案1:回到正确的密钥查询逻辑(推荐)
恢复kSecClassKey的查询,并补充必要参数适配全设备:
func signString(clearString: String) -> Bool { // 恢复密钥查询参数,补充必要属性适配全设备 let getquery: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrApplicationTag as String: serviceName, kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // 明确查询私钥 kSecReturnRef as String: true, kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly // 指定密钥访问权限 ] var item: CFTypeRef? let status = SecItemCopyMatching(getquery as CFDictionary, &item) print("status = ", status) guard status == errSecSuccess else { print("No key found, status: \(status)") return false } // 安全转换类型,避免强转崩溃 guard let privateKey = item as? SecKey else { print("Retrieved item is not a SecKey") return false } self.privateKey = privateKey let data = clearString.data(using: .utf8)! as CFData let algorithm: SecKeyAlgorithm = .ecdsaSignatureMessageX962SHA256 guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else { print("Algorithm Not Supported") return false } var error: Unmanaged<CFError>? guard let signature = SecKeyCreateSignature(privateKey, algorithm, data, &error) as Data? else { print("signature error: \(error?.takeRetainedValue() ?? CFError())") return false } self.signedString = signature.base64EncodedString() return true }
- 补充
kSecAttrKeyClass明确查询私钥,避免歧义 - 添加
kSecAttrAccessible指定密钥访问权限,解决部分设备的权限兼容问题 - 用
guard let做安全类型转换,避免强制转换引发的崩溃
方案2:如果必须用kSecClassGenericPassword存储密钥
若因特殊需求需将密钥存在GenericPassword中,需先将密钥导出为Data存储,读取时再导入为SecKey:
func signString(clearString: String) -> Bool { let getquery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: serviceName, kSecReturnData as String: true, // 返回存储的密钥Data,而非属性 kSecMatchLimit as String: kSecMatchLimitOne // 仅获取一个结果 ] var item: CFTypeRef? let status = SecItemCopyMatching(getquery as CFDictionary, &item) print("status = ", status) guard status == errSecSuccess, let keyData = item as? Data else { print("No key data found") return false } // 将导出的Data重新导入为SecKey let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate ] guard let privateKey = SecKeyCreateWithData(keyData as CFData, attributes as CFDictionary, nil) else { print("Failed to import SecKey from data") return false } self.privateKey = privateKey // 后续签名逻辑与之前一致 let data = clearString.data(using: .utf8)! as CFData let algorithm: SecKeyAlgorithm = .ecdsaSignatureMessageX962SHA256 guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else { print("Algorithm Not Supported") return false } var error: Unmanaged<CFError>? guard let signature = SecKeyCreateSignature(privateKey, algorithm, data, &error) as Data? else { print("signature error: \(error?.takeRetainedValue() ?? CFError())") return false } self.signedString = signature.base64EncodedString() return true }
关键注意点
- 不要用
kSecClassGenericPassword存储SecKey对象,两者存储类型完全不匹配 - 避免使用
as!强制类型转换,改用as?配合guard let做安全校验,提前发现类型错误 - 查询密钥时必须明确
kSecAttrKeyClass(私钥/公钥),避免返回不符合预期的密钥
内容的提问来源于stack exchange,提问作者Hilal
相关产品推荐
相关产品推荐

