ios 添加“kSecAttrSynchronizable”将停止保存privateKey

q9rjltbz  于 2023-08-08  发布在  iOS
关注(0)|答案(2)|浏览(197)

我使用下面的代码将私钥(端到端加密所需)保存到密钥链中。如果我取出带有kSecAttrSynchronizable as String: kCFBooleanTrue!,的行,则密钥被正确保存。似乎是这一行导致了错误。我正在尝试获取私钥以在所有iCloud设备上同步。如果你能帮我解决这事我会很感激的。

func save(userUID: String, privatekey: String) {
    let passwordData = privatekey.data(using: .utf8)!
    
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrSynchronizable as String: kCFBooleanTrue!,
        kSecAttrService as String: "hustles/\(userUID)",
        kSecAttrAccount as String: userUID,
        kSecValueData as String: passwordData
    ]
    SecItemAdd(query as CFDictionary, nil)
}

字符串

8gsdolmq

8gsdolmq1#

解决方案是也通过添加“kSecAttrSynchronizable as String:kCFBooleanTrue!保存查询必须与读取查询匹配。

fd3cxomn

fd3cxomn2#

首先,最好指定kSecAttrAccessible key来指示何时可以访问密钥链项,比如kSecAttrAccessibleWhenUnlocked mentioned here
并确保kSecAttrServicekSecAttrAccountkSecAttrSynchronizable的组合必须是唯一的,如explained here
也就是说,kSecAttrSynchronizable的存在不应该固有地导致保存操作失败。通常,在这些情况下,最好的方法是检查SecItemAdd(或其他Keychain API调用)返回的状态,以获得详细的错误信息。
正如ahmedanswer中所述,如果你保存的密钥链项具有特定属性(如kSecAttrSynchronizable设置为kCFBooleanTrue),那么当你试图读取(或查询)该项时,你还必须指定 * 相同 * 属性才能成功检索它。保存操作中使用的属性本质上是为密钥链项设置“条件”,当您查询它时,您需要匹配这些条件。
因此,如果您保存一个密钥链项时,kSecAttrSynchronizable设置为true,则读取/查询函数也应该包括kSecAttrSynchronizable设置为true
如果保存函数是:

let saveQuery: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrSynchronizable as String: kCFBooleanTrue!,
    kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
    kSecAttrService as String: "hustles/\(userUID)",
    kSecAttrAccount as String: userUID,
    kSecValueData as String: passwordData
]
SecItemAdd(saveQuery as CFDictionary, nil)

字符串
那么你的read函数必须是(灵感来自this answer):

func retrievePrivateKey(for userUID: String) -> String? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrSynchronizable as String: kCFBooleanTrue!,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
        kSecAttrService as String: "hustles/\(userUID)",
        kSecAttrAccount as String: userUID,
        kSecReturnData as String: kCFBooleanTrue!,
        kSecMatchLimit as String: kSecMatchLimitOne
    ]
    
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    
    guard status == errSecSuccess else {
        return nil
    }
    
    if let keyData = item as? Data,
       let keyString = String(data: keyData, encoding: .utf8) {
        return keyString
    }
    
    return nil
}


kSecMatchLimit as String: kSecMatchLimitOne确保只返回一个项目(这对我们的用例来说是有意义的,因为每个UID应该只有一个与之相关的私钥)。
这样可以确保read函数中的搜索条件与保存项目时设置的属性相匹配,这样您就可以成功地从密钥链中检索它。

相关问题