钥匙串访问不返回kSecValueData

时间:2013-05-22 17:34:40

标签: ios macos keychain

我正在使用以下代码:

+ (void)createKeychainItem:(NSString *)name
{
    // Don't create if one already exists
    if ([self getKeychainItem:name] != nil) return;

    NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *attributes = @{

                                 (id)kSecAttrAccount : encodedName,
                                 (id)kSecAttrGeneric : encodedName,
                                 (id)kSecAttrLabel   : name,
                                 (id)kSecAttrService : name,
                                 (id)kSecClass       : (id)kSecClassGenericPassword,
                                 };
    OSStatus result = SecItemAdd((CFDictionaryRef)attributes, NULL);
}

+ (NSDictionary *)getKeychainItem:(NSString *)name
{
    // Build the query
    NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *query = @{
                            (id)kSecAttrAccount : encodedName,
                            (id)kSecAttrGeneric : encodedName,
                            (id)kSecAttrService : name,
                            (id)kSecClass : (id)kSecClassGenericPassword,
                            (id)kSecMatchLimit : (id)kSecMatchLimitOne,
                            (id)kSecReturnAttributes : (id)kCFBooleanTrue,
                            };
    NSDictionary *output = nil;

    OSStatus result = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&output);

    // Convert the password if it exists
    NSData *passwordData = [output objectForKey:kSecValueData];
    if (passwordData != nil) {
        NSMutableDictionary *mutableOutput = [[output mutableCopy] autorelease];
        NSString *password = [[[NSString alloc] initWithBytes:passwordData length:passwordData.length encoding:NSUTF8StringEncoding] autorelease];
        [mutableOutput setObject:password forKey:(id)kSecValueData];
        output = [[mutableOutput copy] autorelease];
    }

    return output;
}

+ (void)updateKeychainItem:(NSString *)name value:(NSString *)value attribute:(id)attribute
{
    // Get the item
    NSDictionary *values = [self getKeychainItem:name];

    // If we got nothing back, build it
    if (values == nil) {
        [self createKeychainItem:name];
    }

    // Create a query to update
    NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *query = @{
                            (id)kSecAttrAccount : encodedName,
                            (id)kSecAttrGeneric : encodedName,
                            (id)kSecAttrService : name,
                            (id)kSecClass : (id)kSecClassGenericPassword,
                            };
    NSDictionary *attributes = nil;
    if (attribute == kSecValueData) {
        attributes = @{ (id)kSecValueData : [value dataUsingEncoding:NSUTF8StringEncoding] };
    } else {
        attributes = @{ attribute : value };
    }

    OSStatus result = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
}

使用[self updateKeychainItem:AuthTokenIdentifer value:authToken attribute:kSecValueData];设置值有效,我可以在Keychain Access中看到它。

使用NSDictionary *values = [self getKeychainItem:AuthTokenIdentifer];获取结果有效,但kSecValueData未在字典中设置。其他所有内容都设置,如创建和修改日期,而不是安全数据。

有什么想法吗?这种情况发生在iOS和Mac上。

1 个答案:

答案 0 :(得分:0)

您需要使用getKeychainItem中的属性字典:来获取值。像

这样的东西
NSMutableDictionary *dataQuery = [attrs mutableCopy];
[dataQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[dataQuery setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];

CFTypeRef resultData;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(dataQuery), &resultData);
NSData *tokenData = CFBridgingRelease(resultData);