2011-12-27 43 views
3

過去幾天我一直在玩Cocoa,我想知道如何去列出我創建的鑰匙串的所有Name/Account對。 Mac OS X附帶的小型鑰匙鏈訪問應用程序可以做到這一點,所以我認爲這一定是可能的?是SecItemCopyMatching我在找什麼?但是,如何指定我想要搜索的鑰匙串?在這種情況下什麼是服務名稱?在Mac OS X上的鑰匙串中列出條目

......我是唯一一個認爲可可中的Keychain API絕對可怕的人嗎?在過去的幾個小時左右,我一直在閱讀文檔,我仍然無處可尋: -/

+0

我碰巧同意鑰匙扣API是相當可怕的,但平心而論可可,它是_not_一個Cocoa API,但是一個很好的舊的Carbon API。 'OSStatus'返回碼是一個贈品。 – Monolo 2011-12-28 10:57:55

回答

2

嗯,我設法枚舉鑰匙串條目,但密碼字段爲空。我認爲如果需要授權,程序會自動要求密鑰鏈密碼,就像它通常那樣?

NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: 
         (id)kSecClassInternetPassword, kSecClass, 
         (id)kCFBooleanTrue, kSecReturnData, 
         (id)kCFBooleanTrue, kSecReturnAttributes, 
         kSecMatchLimitAll, kSecMatchLimit, 
         nil]; 

NSArray *itemDicts = nil; 
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&itemDicts); 
if (status) 
    [MessageBox Show:(NSString*)SecCopyErrorMessageString(status, NULL)]; 

NSMutableArray *arr = [[NSMutableArray alloc] init]; 

for (NSDictionary *itemDict in itemDicts) { 
    NSData *data = [itemDict objectForKey:(id)kSecValueData]; 
    NSString *pwd = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 
    NSString *acc = [itemDict objectForKey:(id)kSecAttrAccount]; 
    NSString *name = [itemDict objectForKey:(id)kSecAttrLabel]; 

    if(acc != nil) { 
     NSArray *values = [NSArray arrayWithObjects: (id)name, (id)acc, (id)pwd, nil]; 

     [arr addObject:(id)values]; 
    } 
} 
[itemDicts release]; 

NSInteger c  = arr.count; 
NSString *cnt = [NSString stringWithFormat:@"%d", c]; 
[MessageBox Show: [arr objectAtIndex:10]]; 
+1

我的半天頭果然是kSecMatchLimit> 1與kSecReturnData不兼容。你可以在http://www.opensource.apple.com找到SecItem.cpp的源代碼,你會發現這樣的評論://如果我們要返回所有匹配,那麼我們不支持獲取密碼作爲數據(這可能需要每個認證) – bitmusher 2012-10-31 21:37:07

7

您遍歷在您的鑰匙串中的項目與SecItemCopyMatchingSecKeychainFindInternetPasswordSecKeychainFindGenericPassword訪問密碼。

遍歷鑰匙扣

// iterates over keychain and pass every item found by the query to PrintAccount. 
static void IterateOverKeychain() { 
    // create query 
    CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 
    CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue); 
    CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); 
    CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); 

    // get search results 
    CFArrayRef result = nil; 
    OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&result); 
    assert(status == 0); 

    // do something with the result 
    CFRange range = CFRangeMake(0, CFArrayGetCount(result)); 
    CFArrayApplyFunction(result, range, PrintAccount, nil); 
} 

// prints the password for a item from the keychain. 
static void PrintAccount(const void *value, void *context) { 
    CFDictionaryRef dict = value; 
    CFStringRef acct = CFDictionaryGetValue(dict, kSecAttrAccount); 
    NSLog(@"%@", acct); 
} 

打印密碼

static void PrintPassword() { 
    const char *acct = "[email protected]"; 
    UInt32 acctLen = (UInt32)strlen(acct); 

    const char *srvr = "calendar.google.com"; 
    UInt32 srvrLen = (UInt32)strlen(srvr); 

    UInt32 pwLen = 0; 
    void *pw = 0; 

    SecKeychainFindInternetPassword(nil, srvrLen, srvr, 0, nil, acctLen, acct, 0, nil, 0, kSecProtocolTypeAny, kSecAuthenticationTypeAny, &pwLen, &pw, nil); 

    CFStringRef pwString = CFStringCreateWithBytes(kCFAllocatorDefault, pw, pwLen, kCFStringEncodingUTF8, NO); 
    NSLog(@"%s %@", acct, pwString); 
}