iOS keyChain

一、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);
}

posted @ 2016-09-04 22:45  wwh99  阅读(332)  评论(0编辑  收藏  举报