web-dev-qa-db-fra.com

Énumérer tous les éléments du trousseau dans mon application iOS

Quelle est la manière la plus simple d'obtenir par programme (depuis mon application) tous les éléments stockés dans le trousseau?

Cela a probablement quelque chose à voir avec SecItemCopyMatching (), mais la documentation de cette fonction n'est pas très claire (et je n'ai pas réussi à trouver un échantillon décent sur le Web).

39
noamtm

SecItemCopyMatching est le bon appel pour cela. D'abord, nous construisons notre dictionnaire de requêtes afin que les attributs des éléments soient retournés dans les dictionnaires et que tous les éléments soient retournés:

NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
    (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
    (__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
    nil];

Comme SecItemCopyMatching requiert au moins la classe des SecItems retournés, nous créons un tableau avec toutes les classes…

NSArray *secItemClasses = [NSArray arrayWithObjects:
                           (__bridge id)kSecClassGenericPassword,
                           (__bridge id)kSecClassInternetPassword,
                           (__bridge id)kSecClassCertificate,
                           (__bridge id)kSecClassKey,
                           (__bridge id)kSecClassIdentity,
                           nil];

… Et pour chaque classe, définissez la classe dans notre requête, appelez SecItemCopyMatching et enregistrez le résultat.

for (id secItemClass in secItemClasses) {
    [query setObject:secItemClass forKey:(__bridge id)kSecClass];

    CFTypeRef result = NULL;
    SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
    NSLog(@"%@", (__bridge id)result);
    if (result != NULL) CFRelease(result);
}

Dans le code de production, vous devez vérifier que le OSStatus renvoyé par SecItemCopyMatching est soit errSecItemNotFound (aucun élément trouvé) ou errSecSuccess (au moins un élément a été trouvé ).

53
Tammo Freese

mise à jour de Swift 4 vers la réponse @Cosmin

open func getAllKeyChainItemsOfClass(_ secClass: String) -> [String:String] {

            let query: [String: Any] = [
                kSecClass as String : secClass,
                kSecReturnData as String  : kCFBooleanTrue,
                kSecReturnAttributes as String : kCFBooleanTrue,
                kSecReturnRef as String : kCFBooleanTrue,
                kSecMatchLimit as String: kSecMatchLimitAll
            ]

            var result: AnyObject?

            let lastResultCode = withUnsafeMutablePointer(to: &result) {
                SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
            }

            var values = [String:String]()
            if lastResultCode == noErr {
                let array = result as? Array<Dictionary<String, Any>>

                for item in array! {
                    if let key = item[kSecAttrAccount as String] as? String,
                        let value = item[kSecValueData as String] as? Data {
                        values[key] = String(data: value, encoding:.utf8)
                    }
                }
            }

            return values
        }
8
uplearnedu.com

Version Swift 3+ qui renvoie également les clés (kSecAttrAccount):

open func getAllKeyChainItemsOfClass(_ secClass: String) -> [String:String] {

        let query: [String: Any] = [
            kSecClass : secClass,
            kSecReturnData  : kCFBooleanTrue,
            kSecReturnAttributes : kCFBooleanTrue,
            kSecReturnRef : kCFBooleanTrue,
            kSecMatchLimit : kSecMatchLimitAll
        ]

        var result: AnyObject?

        let lastResultCode = withUnsafeMutablePointer(to: &result) {
            SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
        }

        var values = [String:String]()
        if lastResultCode == noErr {
            let array = result as? Array<Dictionary<String, Any>>

            for item in array! {
                if let key = item[kSecAttrAccount] as? String, 
                   let value = item[kSecValueData] as? Data {
                   values[key] = String(data: value, encoding:.utf8) 
                }
            }
        }

        return values
    }
5
Cosmin

Version Swift 3 avec xcode 9.1

func getAllKeyChainItemsOfClass(_ secClass: String) -> [String:String] {

    let query: [String: Any] = [
        kSecClass as String : secClass,
        kSecReturnData as String  : kCFBooleanTrue,
        kSecReturnAttributes as String : kCFBooleanTrue,
        kSecReturnRef as String : kCFBooleanTrue,
        kSecMatchLimit as String : kSecMatchLimitAll
    ]

    var result: AnyObject?

    let lastResultCode = withUnsafeMutablePointer(to: &result) {
        SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
    }

    var values = [String:String]()
    if lastResultCode == noErr {
        let array = result as? Array<Dictionary<String, Any>>

        for item in array! {
            if let key = item[kSecAttrAccount as String] as? String,
                let value = item[kSecValueData as String] as? Data {
                values[key] = String(data: value, encoding:.utf8)
            }
        }
    }

    return values
}

Peut être appelé comme:

debugPrint(getAllKeyChainItemsOfClass(kSecClassGenericPassword as String))
3
ergunkocak

Mis à jour pour inclure les informations kSecClassIdentity et kSecClassCertificate dans le dictionnaire

Je ne pense pas non plus qu'il soit nécessaire d'appeler avecUnsafeMutablePointer (à: _:) .

func getAllKeyChainItemsOfClass(_ secClass: String) -> [String:AnyObject] {

    let query: [String: Any] = [
        kSecClass as String : secClass,
        kSecReturnData as String  : true,
        kSecReturnAttributes as String : true,
        kSecReturnRef as String : true,
        kSecMatchLimit as String: kSecMatchLimitAll
    ]

    var result: AnyObject?

    let lastResultCode = withUnsafeMutablePointer(to: &result) {
        SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
    }

//  this also works, although I am not sure if it is as save as calling withUnsafeMutabePointer
//  let lastResultCode = SecItemCopyMatching(query as CFDictionary, &result)

    var values = [String: AnyObject]()
    if lastResultCode == noErr {
        let array = result as? Array<Dictionary<String, Any>>

        for item in array! {
            if let key = item[kSecAttrAccount as String] as? String,
                let value = item[kSecValueData as String] as? Data {
                values[key] = String(data: value, encoding:.utf8) as AnyObject?
            }
            // including identities and certificates in dictionary
            else if let key = item[kSecAttrLabel as String] as? String,
                let value = item[kSecValueRef as String] {
                values[key] = value as AnyObject
            }
        }
    }

    return values
}
0
Chris Graf