2012-06-10 3 views
29

Какой простой способ программно (из моего приложения) получить все элементы, хранящиеся в цепочке ключей?Перечислить все элементы Keychain в приложении iOS

Возможно, что-то связано с SecItemCopyMatching(), но документация для этой функции не очень ясна (и я не смог найти достойный образец в Интернете).

ответ

46

SecItemCopyMatching - правильный звонок для этого. Сначала мы строим наш словарь запросов, так что все атрибуты, элементы возвращаются в словарях, и что все элементы будут возвращены:

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

Как SecItemCopyMatching требует, по крайней мере, класса возвращенных SecItem с, мы создаем массив со всеми классы ...

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

... и для каждого класса, установить класс в нашем запросе, вызовите SecItemCopyMatching и войти результат.

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); 
} 

В производстве код, вы должны проверить, что OSStatus возвращаемый SecItemCopyMatching не либо errSecItemNotFound (никаких пунктов найден) или errSecSuccess (по крайней мере, один пункт был найден).

+0

Спасибо! Еще не проверял его, но выглядит как правильный ответ. – noamtm

+2

Это так. Я протестировал его :) –

+0

Я получил всю нулевую печать как в iPhone, так и в симуляторе. Есть ли что-то еще, что я должен сделать? – karim

3

Swift 3+ версия, которая возвращает также ключи (kSecAttrAccount):

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

     var 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 
    } 
+0

С помощью Swift 3 на Xcode 9.2 это сбой на 'let key: String = item [kSecAttrAccount] как! String' с 'Невозможно передать значение типа '__NSCFData' (0x109b30348) в 'NSString' (0x1069030d0) .'. Я не знаю, почему. –

+1

Изменение строк, которые задают ключ и значение для этого, не произошло, но он устраняет несколько объектов, которые я не уверен, как вытащить: 'if let key = item [kSecAttrAccount] as? String, let value = item [kSecValueData] как? Данные {' –

0

Swift 3 версии с Xcode 9.1

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

    var 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 
} 

Можно назвать как:

debugPrint(getAllKeyChainItemsOfClass(kSecClassGenericPassword as String)) 
Смежные вопросы