我正在使用以下代码:
+ (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上。
答案 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);