一、Keychain 基础
1.iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,密钥等.苹果自己用keychain来保存Wi-Fi网络密码,VPN凭证等等.
2.Keychain的信息是存在于每个应用的沙盒之外,卸载应用并不会把存在Keychain里的信息删除.
3.它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的.
4.Secltem有五类:通用密码,互联网密码,证书,密钥和身份.
5.用原生的Security.framework 就可以实现钥匙串的访问,读写,但是只能在真机上进行.
6.每一个keyChain的组成如图,整体是一个字典结构.
1.kSecClass key 定义属于那一种类型的keyChain
CFTypeRef kSecClassGenericPassword //一般密码
CFTypeRef kSecClassInternetPassword //网络密码
CFTypeRef kSecClassCertificate //证书
CFTypeRef kSecClassKey //密钥
CFTypeRef kSecClassIdentity //身份
2.不同类型的kSecClass key包含不同的属性,这些attributes定义了这个item的具体信息
3.每个item可以包含一个密码项来存储对应的密码
二、Keychain 操作
引入Security包,引入文件 #import <Security/Security.h>
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使用
在对Keychain item进行操作时,一般的步骤如下:
1、创建一个NSMutableDictionary对象,用于存储或用来设置query条件
2、设置kSecClass,指明我需要获取什么类型数据
3、设置对应的kSecAttr属性,用来指明我需要对哪个Keychain item进行操作。
4、调用IOS中的增删改查函数,传入字典查询条件,并获得对应的结果。
+ (NSMutableDictionary *)query:(NSString *)service { return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword, (__bridge_transfer id)kSecClass, service, (__bridge_transfer id)kSecAttrService, service, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock, (__bridge_transfer id)kSecAttrAccessible, nil]; }
+ (void)save:(NSString *)service data:(id)data { NSMutableDictionary *keyChainQuery = [self query:service]; SecItemDelete((__bridge_retained CFDictionaryRef)keyChainQuery); [keyChainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData]; SecItemAdd((__bridge_retained CFDictionaryRef)keyChainQuery, NULL); }
- (void)update { NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, password,kSecAttrAccount, kCFBooleanTrue,kSecReturnAttributes,nil]; CFTypeRef result = nil; (SecItemCopyMatching((CFDictionaryRef)query, &result) == noErr) { NSMutableDictionary* update = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)result]; [update setObject:[query objectForKey:kSecClass] forKey:kSecClass]; [update setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:kSecValueData]; [update removeObjectForKey:kSecClass]; NSMutableDictionary* updateItem = [NSMutableDictionary dictionaryWithDictionary:result]; [updateItem setObject:[query objectForKey:()kSecClass] forKey:()kSecClass]; OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)update); } }
+ (void)delete:(NSString *)service { NSMutableDictionary *keyChainQuery = [self query:service]; SecItemDelete((__bridge_retained CFDictionaryRef)keyChainQuery); }