1

出于某种原因,在 OSX 10.8.4 上调用 SecItemCopyMatching 时,我得到了一个空字典。对应的项目在钥匙串中,包含用户名和密码。SecItemCopyMatching 找到它(errSecSuccess),但结果字典只包含 0 个条目。我希望它至少有用户名和密码数据,那么我的请求有什么问题?

OSStatus status;
NSMutableDictionary *query = [NSMutableDictionary dictionary];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)kSecReturnAttributes forKey:(id)kCFBooleanTrue];
[query setObject:@"MyService" forKey:(id)kSecAttrService];

CFDictionaryRef dictRef = NULL;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dictRef);
if (status != errSecSuccess) {
    CFStringRef errorRef = SecCopyErrorMessageString(status, NULL);
    NSLog(@"%s: %@", __FUNCTION__, (__bridge NSString *)errorRef);
    CFRelease(errorRef);
    return nil;
}

// --> dictRef empty

if (dictRef != NULL) CFRelease(dictRef);

在此处输入图像描述

4

1 回答 1

2

请求中有错误。我混淆了键和对象。

[query setObject:(id)kSecReturnAttributes forKey:(id)kCFBooleanTrue];

一定是

[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];

但是正如 bdash 指出的那样,它只会返回非加密属性,如用户名。要获取密码,还需要通过另一个请求

[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];

所以这里是我现在拥有的:

OSStatus status;
NSMutableDictionary *query = [NSMutableDictionary dictionary];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
[query setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
[query setObject:@"MyService" forKey:(id)kSecAttrService];

// get username
CFDictionaryRef dictRef = NULL;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dictRef);
if (status != errSecSuccess) {
    CFStringRef errorRef = SecCopyErrorMessageString(status, NULL);
    NSLog(@"%s: %@", __FUNCTION__, (__bridge NSString *)errorRef);
    CFRelease(errorRef);
    return nil;
}

NSString *username = (__bridge NSString *)CFDictionaryGetValue(dictRef, kSecAttrAccount);
CFRelease(dictRef);

// get password
[query removeObjectForKey:(id)kSecReturnAttributes];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
CFDataRef dataRef = NULL;
status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dataRef);
if (status != errSecSuccess) {
    CFStringRef errorRef = SecCopyErrorMessageString(status, NULL);
    NSLog(@"%s: %@", __FUNCTION__, (__bridge NSString *)errorRef);
    CFRelease(errorRef);
    return nil;
}

NSString *password = [[NSString alloc] initWithData:(__bridge NSData *)(dataRef) encoding:NSUTF8StringEncoding];
CFRelease(dataRef);
于 2013-06-27T08:30:03.390 回答