我使用的是apple 上提供的sample code KeychainItemWrapper 在此基础上进行修改
相关链接:
http://useyourloaf.com/blog/2010/04/28/keychain-duplicate-item-when-adding-password.html
http://stackoverflow.com/questions/7249297/convert-nsdictionary-to-nsdata
1.在keychain的kSecValueData中存储的数据必须是NSData类型,否则无法存储。所以就需要将NSDictionary转换成NSData
- (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert
{
// The assumption is that this method will be called with a properly populated dictionary
// containing all the right key/value pairs for a SecItem.
// Create a dictionary to return populated with the attributes and data.
NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];
// Add the Generic Password keychain item class attribute.
[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
// Convert the NSString to NSData to meet the requirements for the value type kSecValueData.
// This is where to store sensitive data that should be encrypted.
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:[dictionaryToConvert objectForKey:(id)kSecValueData] forKey:@"Some Key Value"];
[archiver finishEncoding];
[archiver release];
// Here, data holds the serialized version of your dictionary
// do what you need to do with it before you:
[returnDictionary setObject:data forKey:(id)kSecValueData];
[data release];
return returnDictionary;
}
2.取数据时需要将NSData 转换成NSDictionary
- (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert
{
// The assumption is that this method will be called with a properly populated dictionary
// containing all the right key/value pairs for the UI element.
// Create a dictionary to return populated with the attributes and data.
NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];
// Add the proper search key and class attribute.
[returnDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
// Acquire the password data from the attributes.
NSData *passwordData = NULL;
//NSMutableDictionary *passwordData = nil;
if (SecItemCopyMatching((CFDictionaryRef)returnDictionary, (CFTypeRef *)&passwordData) == noErr)
{
// Remove the search, class, and identifier key/value, we don't need them anymore.
[returnDictionary removeObjectForKey:(id)kSecReturnData];
// Add the password to the dictionary, converting from NSData to NSString.
NSData *d = [[NSMutableData alloc] initWithData:passwordData];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:d];
NSDictionary *myDictionary = [[unarchiver decodeObjectForKey:@"Some Key Value"] retain];
[unarchiver finishDecoding];
[unarchiver release];
[returnDictionary setObject:myDictionary forKey:(id)kSecValueData];
[d release];
}
else
{
// Don't do anything if nothing is found.
NSAssert(NO, @"Serious error, no matching item found in the keychain.\n");
}
[passwordData release];
return returnDictionary;
}
3.更改genericPasswordQuery、keychainItemData属性
[self.genericPasswordQuery setObject:identifier forKey:(id)kSecAttrAccount];
[self.keychainItemData setObject:identifier forKey:(id)kSecAttrAccount];