web-dev-qa-db-ja.com

iOSアプリケーションのすべてのキーチェーンアイテムを列挙する

プログラムで(アプリ内から)すべてのアイテムをキーチェーンに保存する最も簡単な方法は何ですか?

おそらくSecItemCopyMatching()と関係がありますが、その関数のドキュメントはあまり明確ではありません(Web上で適切なサンプルを見つけることができませんでした)。

39
noamtm

SecItemCopyMatchingはそのための正しい呼び出しです。最初にクエリディクショナリを作成して、アイテムの属性がディクショナリで返され、すべてのアイテムが返されるようにします。

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

SecItemCopyMatchingには少なくとも返されたSecItemsのクラスが必要なので、すべてのクラスを含む配列を作成します…

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が返すSecItemCopyMatchingerrSecItemNotFound(アイテムが見つからない)またはerrSecSuccess(少なくとも1つのアイテムが見つかった)であることを確認する必要があります)。

53
Tammo Freese

@ Cosmin回答へのSwift 4の更新

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

キーも返す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
    }
5
Cosmin

Xcode 9.1のSwift 3バージョン

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
}

次のように呼び出すことができます:

debugPrint(getAllKeyChainItemsOfClass(kSecClassGenericPassword as String))
3
ergunkocak

kSecClassIdentityおよびkSecClassCertificate情報を辞書に含めるように更新

また、withUnsafeMutablePointer(to:_:)を呼び出す必要があるとも思いません。

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