iOS keyChain 整理

KeyChain是iOS设备中用于安全存储敏感信息如用户名、密码和认证令牌的容器。它是一个加密的sqlite数据库,即使App被删除,数据依然保留。KeyChain的结构包括类、一般属性、查找属性和返回类型。操作KeyChain主要通过Security.framework的四个方法:查找、添加、更新和删除。通常,添加操作会检查是否已存在相同项,以决定是更新还是添加。

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值