最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - Unable to fetch key from Keychain in Swift - Stack Overflow

programmeradmin2浏览0评论

I am saving a private key to keychain and now want to retrieve it but some how not able to do it. Following is my code:

public func storeKeyToKeychain(_ key: SecKey, tag: String) -> Bool {
    let deleteQuery: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrApplicationTag as String: tag.data(using: .utf8)!
    ]
    SecItemDelete(deleteQuery as CFDictionary)  // Clean existing key before adding

    let query: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrApplicationTag as String: tag.data(using: .utf8)!,
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecValueRef as String: key,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
    ]
    
    let status = SecItemAdd(query as CFDictionary, nil)
    if status != errSecSuccess {
        print("Key storage failed with status: \(status) (\(SecCopyErrorMessageString(status, nil) ?? "Unknown error" as CFString))")
    } else {
        print("Key stored successfully.")
    }
    return status == errSecSuccess
}

public func getKeyFromKeychain(tag: String) -> SecKey? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrApplicationTag as String: tag.data(using: .utf8)!,  // Ensure tag is Data
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecReturnRef as String: true  // Retrieve the SecKey reference
    ]
    
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    
    if status == errSecSuccess, let key = item as! SecKey? {
        print("Successfully retrieved SecKey.")
        return key
    } else if status == errSecItemNotFound {
        print("Key not found in the Keychain.")
    } else {
        print("Keychain retrieval failed with status: \(status) (\(SecCopyErrorMessageString(status, nil) ?? "Unknown error" as CFString))")
    }
    return nil
}

I can see the Key stored successfully message. So key is saved but when I try to fetch it, I getting nil in item which means I am not able to fetch it. I have checked in logs that errSecSuccess is true while fetching it but still I am unable to get the key in item.

I am saving a private key to keychain and now want to retrieve it but some how not able to do it. Following is my code:

public func storeKeyToKeychain(_ key: SecKey, tag: String) -> Bool {
    let deleteQuery: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrApplicationTag as String: tag.data(using: .utf8)!
    ]
    SecItemDelete(deleteQuery as CFDictionary)  // Clean existing key before adding

    let query: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrApplicationTag as String: tag.data(using: .utf8)!,
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecValueRef as String: key,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
    ]
    
    let status = SecItemAdd(query as CFDictionary, nil)
    if status != errSecSuccess {
        print("Key storage failed with status: \(status) (\(SecCopyErrorMessageString(status, nil) ?? "Unknown error" as CFString))")
    } else {
        print("Key stored successfully.")
    }
    return status == errSecSuccess
}

public func getKeyFromKeychain(tag: String) -> SecKey? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrApplicationTag as String: tag.data(using: .utf8)!,  // Ensure tag is Data
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecReturnRef as String: true  // Retrieve the SecKey reference
    ]
    
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    
    if status == errSecSuccess, let key = item as! SecKey? {
        print("Successfully retrieved SecKey.")
        return key
    } else if status == errSecItemNotFound {
        print("Key not found in the Keychain.")
    } else {
        print("Keychain retrieval failed with status: \(status) (\(SecCopyErrorMessageString(status, nil) ?? "Unknown error" as CFString))")
    }
    return nil
}

I can see the Key stored successfully message. So key is saved but when I try to fetch it, I getting nil in item which means I am not able to fetch it. I have checked in logs that errSecSuccess is true while fetching it but still I am unable to get the key in item.

Share Improve this question edited Nov 28, 2024 at 10:20 pankaj asked Nov 28, 2024 at 10:06 pankajpankaj 8,39816 gold badges74 silver badges118 bronze badges 1
  • In your use case, you don't need to specify the attribute kSecAttrKeyType. Have you tried removing this from the queries for adding and getting? Note, that the key itself has been created with an attribute kSecAttrKeyType. Possibly it conflicts with your setting in the query and what actually has been set when creating it? – CouchDeveloper Commented Nov 29, 2024 at 12:14
Add a comment  | 

1 Answer 1

Reset to default -1

Try with this code. I am using this one and it works fine.

class KeychainAccess {
    
    func addKeychainData(itemKey: String, itemValue: String) throws {
        guard let valueData = itemValue.data(using: .utf8) else {
            print("Keychain: Unable to store data, invalid input - key: \(itemKey), value: \(itemValue)")
            return
        }
        
        //delete old value if stored first
        do {
            try deleteKeychainData(itemKey: itemKey)
        } catch {
            print("Keychain: nothing to delete...")
        }
        
        let queryAdd: [String: AnyObject] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: itemKey as AnyObject,
            kSecValueData as String: valueData as AnyObject,
            kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
        ]
        let resultCode: OSStatus = SecItemAdd(queryAdd as CFDictionary, nil)
        
        if resultCode != 0 {
            print("Keychain: value not added - Error: \(resultCode)")
        } else {
            print("Keychain: value added successfully")
        }
    }
    
    func deleteKeychainData(itemKey: String) throws {
        let queryDelete: [String: AnyObject] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: itemKey as AnyObject
        ]
        
        let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)
        
        if resultCodeDelete != 0 {
            print("Keychain: unable to delete from keychain: \(resultCodeDelete)")
        } else {
            print("Keychain: successfully deleted item")
        }
    }
    
    func queryKeychainData (itemKey: String) throws -> String? {
        let queryLoad: [String: AnyObject] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: itemKey as AnyObject,
            kSecReturnData as String: kCFBooleanTrue,
            kSecMatchLimit as String: kSecMatchLimitOne
        ]
        var result: AnyObject?
        let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
            SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
        }
        
        if resultCodeLoad != 0 {
            print("Keychain: unable to load data - \(resultCodeLoad)")
            return nil
        }
        
        guard let resultVal = result as? NSData, let keyValue = NSString(data: resultVal as Data, encoding: String.Encoding.utf8.rawValue) as String? else {
            print("Keychain: error parsing keychain result - \(resultCodeLoad)")
            return nil
        }
        return keyValue
    }
}

Create one object and use that object to store and fetch.

let keychain = KeychainAccess()

     do {
          try? self.keychain.addKeychainData(itemKey: "KeyChainUserName", itemValue: result?.customer?.email ?? "")
 } catch {
     print("error of user Name")
 }

do {
     try? self.keychain.addKeychainData(itemKey: "KeyChainPassword", itemValue: "\(result?.customer?.id ?? 0)" )
  } catch {
          print("error of password")
}

Fetch data from the Keychain.

let userName = try? self.keychain.queryKeychainData(itemKey: "KeyChainUserName")
print("UserName:", userNam)
发布评论

评论列表(0)

  1. 暂无评论