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).
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 SecItem
s 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é ).
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
}
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
}
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))
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
}