KeyChain 介绍
根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌。苹果自己用keychain来保存Wi-Fi网络密码,VPN凭证等等。它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的。相对于NSUserDefaults、文件保存等一般方式,keychain保存更为安全,而且keychain里保存的信息不会因App被删除而丢失,所以在重装App后,keychain里的数据还能使用。
KeyChain的结构
iOS中Keychain Services使用key-value dictionary来指定我们想要创建或者查找的keychain item属性。
一个典型的搜索字典包含以下四部分:
- The class key-value pair:指定了keychain item类型。
- 一个或多个key-value pairs:指定keychain item的各种一般属性
- 一个或多个key-value pairs:指定keychain item的各种查找属性,例如kSecMatchPolicy,为了查找的精确性
一个返回类型的key-value pair:指定想要的返回结果的类型,例如是返回一个dictionary或者persistent reference
KeyChain的操作
iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:
// 查询
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result);
// 添加
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);
// 更新
KeyChain中的ItemOSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef
attributesToUpdate);
// 删除
KeyChain中的ItemOSStatus SecItemDelete(CFDictionaryRef query)
KeyChain的使用
根据特定的service创建一个用于操作KeyChain的Dictionary
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
NSMutableDictionary *keyChainQuery = [[NSMutableDictionary alloc] init];
[keyChainQuery setObject:(__bridge_transfer id)kSecClassGenericPassword forKey:
(__bridge_transfer id)kSecClass];
[keyChainQuery setObject:service forKey:(__bridge_transfer id)kSecAttrService];
[keyChainQuery setObject:service forKey:(__bridge_transfer id)kSecAttrAccount];
[keyChainQuery setObject:(__bridge_transfer
id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge_transfer
id)kSecAttrAccessible];
return keyChainQuery;
}
查找
+ (id)load:(NSString *)server {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:server];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer
id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:
(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
OSStatus status = SecItemCopyMatching((__bridge_retained
CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData);
if (status == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer
NSData *)keyData];
} @catch (NSException *exception) {
NSLog(@"Unarchive of %@ failed: %@",server,exception);
} @finally {
}
}
return ret;
}
添加&更新
当添加的时候我们一般需要判断一下当前钥匙串里面是否存在我们要添加的钥匙。如果已经存在我们就更新,不存在就添加。所以这两个操作一般写成一个函数。
+ (void)save:(NSString *)server data:(id)data {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:server];
// 添加前首先查找是否存在要添加的密码
OSStatus status = SecItemCopyMatching((__bridge_retained
CFDictionaryRef)keychainQuery, nil);
if (status == errSecSuccess) {//item已经存在,更新它
NSMutableDictionary *dic = [[NSMutableDictionary alloc]
initWithDictionary:keychainQuery];
[dic setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:
(__bridge_transfer id)kSecValueData];
SecItemUpdate((__bridge_retained CFDictionaryRef)keychainQuery, (__bridge
CFDictionaryRef)dic);
} else if (status == errSecItemNotFound) {//没有找到则添加
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data]
forKey:(__bridge_transfer id)kSecValueData];
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
}
删除
+ (void)delete:(NSString *)server {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:server];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
KeyChain是iOS设备中用于安全存储敏感信息如用户名、密码和认证令牌的容器。它是一个加密的sqlite数据库,即使App被删除,数据依然保留。KeyChain的结构包括类、一般属性、查找属性和返回类型。操作KeyChain主要通过Security.framework的四个方法:查找、添加、更新和删除。通常,添加操作会检查是否已存在相同项,以决定是更新还是添加。

1645

被折叠的 条评论
为什么被折叠?



