iOS Keychain总结

概要

iOS中一般用Keychain存储密码、私钥等需要加密的数据。参考apple 官网介绍

使用方法

先总的说下怎么使用,再具体说说原理。
我自己实现了几个基本的功能:查找、更新、删除、添加。后续会继续补充更多的功能。
已开源到github

  1. 在工程中添加Secutity.framework库。(TARGETS-General-Linked Frameworks and Libraries)
  2. 使用说明
#import "NYKeychain.h"//引入头文件
NSString *serviceName = xxx;//服务名
NSString *account = xxx;//账户名
//其中serviceName和account在程序内部自己定义的常量,keychain根据这两个量保存、查找、更新、替换密码
[NYKeychain setPassword:password forService:serviceName account:account];//保存、更新密码
[NYKeychain passwordForService:serviceName account:account];//查找
 [NYKeychain deletePasswordForService:serviceName account:account];//删除

原理

keychain相当于一个银行的金库,keychain item就相当于金库里的一个个的保险柜,保存在keychain Item里面的密码就相当于保险柜里面存放的金条。

keychain结构
  • 银行金库里有多个保险柜,keychain有多个keychain item;每个保险柜都有两部分组成:保险柜里面的金条以及保险柜的属性(保险柜编号、保险柜位置……);每一个keychain item包含两部分:数据,一系列属性。
  • 保险柜的属性与其要存放的东西有关:可能存放黄金的保险柜在A区,保险柜编号以G开头;而存放重要资料的保险柜在B区,保险柜编号以D开头……而keychain item属性与其要保存的密码有关:是generic passwords还是Internet passwords。例如Internet passwords的属性有security domain,protocol type等等。
  • 每个人只能打开自己的保险柜,每个iOS应用也只能使用自己的keychain items.
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
    具体可以指定什么属性,可以查找apple官方定义
    例如想要执行一个有如下属性的搜索:想要Apple Store(service name)下ImaUser(account)账户下密码,该搜索条件不敏感,可以用SecItemCopyMatching函数,如图所示:
搜索dictionary

代码详解

与Keychain相关的操作最重要的就是dictionary。所有操作都是围绕配置这个dictionary。
在下面的代码中,首先配置了这个dictionary四个部分的前两个部分,即class key-value pair,一般属性。

- (NSMutableDictionary *)query
{
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
    //要保存的password类型
    [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    if (self.service) {//AttrService 和AttrAccount是两个主要的属性
        [dictionary setObject:self.service forKey:(__bridge id)kSecAttrService];
    }
    if (self.account) {
        [dictionary setObject:self.account forKey:(__bridge id)kSecAttrAccount];
    }
    return dictionary;
}
使用Keychain item 搜索dictionary

apple提供了四个函数用来进行密码的查找、添加、更新、删除等操作。

SecItemAdd;
SecItemUpdate;
SecItemCopyMatching;
SecItemDelete;
  • 查找
    查找前,先配置dictionary。在下面的代码中配置了这个dictionary四个部分的后两个部分,即Search key-value和返回类型的key-value.
 - (BOOL)fetch
{
    CFTypeRef result = NULL;
    NSMutableDictionary *query = [self query];
    //YES本来是一个值,@YES就变成了一个对象,可用[NSNumber numberWithBool];代替
    [query setObject:@YES forKey:(__bridge id)kSecReturnData];
    [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
    if (status != errSecSuccess) {
        return NO;
    }
    self.passwordData = (__bridge_transfer NSData *)result;
    return YES;
}
  • 添加、更新
    添加、更新前首先查找。此处的dictionary只配置了四部分中的前两部分,原因是,apple已经有默认的配置。例如在kSecMatchCaseInsensitive key中有一句话:

if this attribute is not provided, then case-sensitive string matching is performed

 - (BOOL)save
{
    NSMutableDictionary *query = nil;
    NSMutableDictionary *searchQuery = [self query];
    //添加前首先查找是否存在要添加的密码
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchQuery, nil);
    if (status == errSecSuccess) {//item 已经存在,更新它
        query = [[NSMutableDictionary alloc] init];
        [query setObject:self.passwordData forKey:(__bridge id)kSecValueData];
        status = SecItemUpdate((__bridge CFDictionaryRef)searchQuery, (__bridge         CFDictionaryRef)query);
    } else if (status == errSecItemNotFound) {//item未找到,创建它
        query = [self query];
        [query setObject:self.passwordData forKey:(__bridge id)kSecValueData];
        status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
    }
    return (status == errSecSuccess);
}
  • 删除
    删除相对简单,找到了,就删除
 - (BOOL)deleteItem
{
NSMutableDictionary *query = [self query];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
return (status == errSecSuccess);
}

以上内容都是基础,懂了这些,Keychain相关的其它内容也就不难理解了。以后如果用到,会进一步增加其它复杂的功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容