枚举我的iOS应用程序中的所有Keychain项目

noa*_*mtm 37 security keychain ios

以编程方式(在我的应用程序中)最简单的方法是将所有项目存储在钥匙串中?

它可能与SecItemCopyMatching()有关,但该函数的文档不是很清楚(我在网上找不到合适的样本).

Tam*_*ese 53

SecItemCopyMatching对此是正确的要求.首先,我们构建查询字典,以便在字典中返回项的属性,并返回所有项:

NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
    (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
    (__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
    nil];
Run Code Online (Sandbox Code Playgroud)

由于SecItemCopyMatching需要类返回的至少SecItemS,我们创建的所有类的数组...

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

...对于每个类,在查询中设置类,调用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);
}
Run Code Online (Sandbox Code Playgroud)

在生产代码中,您应检查OSStatus返回的SecItemCopyMatchingerrSecItemNotFound(未找到任何项目)或errSecSuccess(至少找到一个项目).

  • 它是.我测试了:) (4认同)

upl*_*com 6

Swift 4更新为@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
        }
Run Code Online (Sandbox Code Playgroud)


Cos*_*min 5

Swift 3+版本还返回了密钥(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
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

其他 Swift 代码片段看起来都有点复杂。您实际上不必过多地处理 MutablePointers,并且您可能希望进行适当的错误管理。我仅通过调整Apple 文档中的代码就在 Swift 中实现了我的版本。此处适用于使用 Xcode 11 的用户。

let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, // change the kSecClass for your needs
                            kSecMatchLimit as String: kSecMatchLimitAll,
                            kSecReturnAttributes as String: true,
                            kSecReturnRef as String: true]
var items_ref: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &items_ref)
guard status != errSecItemNotFound else { throw KeychainError.noPassword }
guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }
let items = items_ref as! Array<Dictionary<String, Any>>

// Now loop over the items and do something with each item
for item in items {
    // Sample code: prints the account name
    print(item[kSecAttrAccount as String] as? String)
}
Run Code Online (Sandbox Code Playgroud)