UserDefaults存加密数据取回报错,求SymmetricKey安全存Keychain方案
解决你的CryptoKit加解密与Keychain存储问题
我来帮你逐一解决这两个问题:
问题1:UserDefaults中取回SealedBox的类型转换错误
你遇到的类型转换错误,核心原因是你存入UserDefaults的是SealedBox的combined Data,但取出时直接尝试将Data强制转换为ChaChaPoly.SealedBox类型——这是行不通的,因为UserDefaults只会存储基础类型(比如Data),不会直接保存自定义对象。
正确的做法是:取出存储的Data后,通过ChaChaPoly.SealedBox(data:)初始化方法还原SealedBox对象。另外,建议不要用try!强制解包,最好用do-catch处理可能的错误(比如数据损坏、密钥不匹配等)。
修正后的decrypt方法:
func decrypt() { guard let savedKeyData = Services.getKeyData(), let sealedBoxData = UserDefaults.standard.data(forKey: "sealedBox"), let sealedBox = try? ChaChaPoly.SealedBox(data: sealedBoxData) else { textView.text = "解密失败:数据或密钥异常" return } do { let retrievedKey = SymmetricKey(data: savedKeyData) let decryptedMessage = try ChaChaPoly.open(sealedBox, using: retrievedKey) textView.text = String(data: decryptedMessage, encoding: .utf8) ?? "无法转换为可读文本" } catch { textView.text = "解密出错:\(error.localizedDescription)" } }
问题2:无需UnsafeBytes存储SymmetricKey到Keychain
从Swift 5.6开始,SymmetricKey遵守了ContiguousBytes协议,你可以直接将它转换为Data,完全不需要使用withUnsafeBytes这种不安全的操作。SwiftKeychainWrapper本身支持直接存储Data类型,所以我们可以优化密钥的存储流程:
优化后的加密方法(存储Data到Keychain)
func encrypt(text: String) { let key = SymmetricKey(size: .bits256) guard let message = text.data(using: .utf8) else { print("文本转Data失败") return } do { let sealedBox = try ChaChaPoly.seal(message, using: key) // 存储SealedBox的合并Data到UserDefaults UserDefaults.standard.set(sealedBox.combined, forKey: "sealedBox") // 直接将SymmetricKey转为Data存储到Keychain let keyData = Data(key) Services.saveKeyData(keyData: keyData) } catch { print("加密出错:\(error.localizedDescription)") } }
对应的Keychain服务方法(修改为处理Data)
把原来处理字符串的Services方法改成直接操作Data:
class Services { static func saveKeyData(keyData: Data) { SwiftKeychainWrapper.standard.set(keyData, forKey: "encryptionKey") } static func getKeyData() -> Data? { return SwiftKeychainWrapper.standard.data(forKey: "encryptionKey") } }
这样就完全避免了UnsafeBytes和Base64编码的额外开销,代码更简洁安全。
内容的提问来源于stack exchange,提问作者Tymek Sala
相关产品推荐
相关产品推荐

