IOS keychain 使用

首先使用keychain 要先导入 Security.framework 这个系统framework,然后在文件里 import 头文件,由于这个框架是c语言风格的接口API,会让人很疑惑,如果想快速集成,推荐这篇文章,如果想弄明白整个API 下面详细讲解

Keychain概览Keychain里可以存储若干条目(item),每个条目都属于某一个类别(class),以下是常见的几种类别:

  • kSecClassInternetPassword 属于该类别的条目往往用来存储上网登录密码,远程服务器密码等
  • kSecClassGenericPassword存储一些通用的密码,比如数据库密码,vpn连接的密码等等
  • kSecClassCertificatekSecClassKeykSecClassIdentity这三类条目往往用于建立基于证书,秘钥和公钥系统的安全连接。

条目类别是一个条目最基本的属性,每个存入keychain的条目,都需要为它制定一个类别。

操作keychain常见的3个方法:

  • SecItemAdd 添加新条目到keychain.
  • SecItemUpdate修改一个已存在keychain里的条目
  • SecItemCopyMatching查询keychain里的条目并且读取条目信息

下面用一张摘取自苹果官方网站的一张图阐述一下一个常见keychain的操作流程,该图以一个应用连接ftp服务器为例

在这里插入图片描述

在上图中,应用大概流程是这样的:应用开始连接ftp服务器,首先查询keychain是否存在服务器密码,如果存在,那么直接取出密码登陆;如果不存在,那么应用弹出对话框要求用户输入,然后进行登陆,如果登陆成功,那么存储密码到keychain。简单来说,如果要存储一个password,需要先遍历Keychain,看它的password是否已经存在于Keychain中,存在的话就更新它的值,不存在就存储。所以这就使用到苹果提供的方法:

// 查询OSStatus SecItemCopyMatching(CFDictionaryRefquery,CFTypeRef*result);// 添加OSStatus SecItemAdd(CFDictionaryRefattributes,CFTypeRef*result);
// 更新OSStatus SecItemUpdate(CFDictionaryRefquery,CFDictionaryRefattributesToUpdate);
// 删除OSStatus SecItemDelete(CFDictionaryRefquery)

接下来看看操作Keychain常用的key-value.kSecClass:有五个值,分别为

  • kSecClassGenericPassword(通用密码--也是接下来使用的)、
  • kSecClassInternetPassword(互联网密码)
  • kSecClassCertificate(证书)
  • kSecClassKey(密钥)
  • kSecClassIdentity(身份)
  • kSecAttrService:服务
  • kSecAttrServer:服务器域名或IP地址
  • kSecAttrAccount:账号
  • kSecAttrAccessGroup:可以在应用之间共享keychain中的数据
  • kSecMatchLimit:返回搜索结果
  • kSecMatchLimitOne 一个
  • kSecMatchLimitAll(全部)

Keychain接口参数所有对keychain接口的操作,参数的传递基本上都用到字典,将所需要的参数放入字典,然后将字典传递给keychain接口。
上面提到的条目类别,就是一个参数,除此之外,操作条目往往还需要条目ID,条目所属服务名,条目所属账户名等。这些参数的名称如下:kSecClass:条目类别kSecAttrGeneric:条目idkSecAttrService:条目所属服务kSecAttrAccount:条目所属账户名其中kSecAttrService和kSecAttrAccount在整个keychain里必须唯一,不能重名。
Keychain条目查询使用SecItemCopyMatching进行查询,查询时,我们需要指明要查询条目的类别(kSecClass),条目的id(kSecAttrGeneric),条目所属的服务和账户(kSecAttrService,kSecAttrAccount)。此外,我们还可以设置其他一些查询条件,比如返回条目的数量(kSecMatchLimit),返回条目的数据类型,比如:
kSecReturnData:返回条目所存储的数据,返回值类型是CFDataRef
kSecReturnAttributes:返回该条目的属性,返回值是字典类型CFDictionaryRefk
SecReturnRef:返回条目的引用,根据条目所属类别,返回值类型可能是:SecKeychainItemRef, SecKeyRef,SecCertificateRef, SecIdentityRef.
kSecReturnPersistentRef:返回条目的引用,返回值类型是CFDataRef
如下代码示例用来查询存储在keychain里的密码

//建立词典,用来传递参数
NSMutableDictionary *dictionary = [[NSMutableDictionary dictionary];
//设置条目类别,我们用该条目存储普通密码,所以设置成kSecClassGenericPassword[dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
//设置条目的id,比如“MyPasswordForFtp",条目id必须时NSDate,而不是
NSStringNSString *itemIDString = @"MyPasswordForFtp";
NSData *itemID= [itemIDString dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:itemIDforKey:(id)kSecAttrGeneric];
//设置条目所属的服务和账户,为了避免重名,我们使用常见的反转域名规则,比如com.mykeychain.ftppassword
NSString *account = @"com.mykeychain.ftppassword";
NSString *service = @"com.mykeychain.ftppassword";
[dictionary setObject:account forKey:(id)kSecAttrAccount];
[dictionary setObject:service forKey:(id)kSecAttrService];//设置查询条件,只返回一个条目[dictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
//设置查询条件,返回条目存储的数据 (kSecReturnData == True)
[dictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
//开始查询NSData *result = nil;OSStatus status = SecItemCopyMatching((CFDictionaryRef)dictionary , (CFTypeRef *)&result);

Keychain条目添加使用SecItemAdd()进行条目添加,我们需要指明新条目的类别(kSecClass),新条目的id(kSecAttrGeneric),新条目所属的服务和账户(kSecAttrService,kSecAttrAccount),此外,还需要指明该条目所存储的数据(kSecValueData),否则,没有数据的条目就没有任何存入keychain的意义了。请看如下代码示例:

//建立词典,用来传递参数
NSMutableDictionary *dictionary = [[NSMutableDictionary dictionary];
//设置条目类别,我们用该条目存储普通密码,所以设置成 kSecClassGenericPassword[dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
//设置条目的id,比如“MyPasswordForFtp",条目id必须时NSDate,而不是NSString
NSString *itemIDString = @"MyPasswordForFtp";
NSData *itemID= [itemIDString dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:itemIDforKey:(id)kSecAttrGeneric];
//设置条目所属的服务和账户,为了避免重名,我们使用常见的反转域名规则,比如com.mykeychain.ftppasswordNSString *account = @"com.mykeychain.ftppassword";
NSString *service = @"com.mykeychain.ftppassword";
[dictionary setObject:account forKey:(id)kSecAttrAccount];
[dictionary setObject:service forKey:(id)kSecAttrService];
//设置条目数据,条目数据时NSDateNSString *password = @"123456";
NSData *itemData = [password dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:itemData forKey:(id)kSecValueData];
//添加条目到
keychainOSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);

keychain条目的修改使用SecItemUpdate()进行条目修改,需要传入两个词典,第一个词典用来查询条目,第二个词典用来传递修改后的新值。查询条目所用的词典设置请看上述Keychain条目查询章节,更新值所用词典里设置要更新的参数和值。这里请注意的是,查询词典里不能设置任何查询条件,比如kSecMatchLimit和kSecReturnData,kSecReturnAttributes等,否则会出错。因为这里的查询是为了更新数据,是以写入为目的,不是真正的查询和读取条目,所以设置这些和读取有关的条件是无意义的,系统会认为是和安全有关的错误,会返回-50(errSecParam)下面代码用来更新密码,要更新的条目id为“MyPasswordForFtp”的条目

//建立查询字典
NSMutableDictionary *searchDictionary = [[NSMutableDictionary dictionary];
//设置查询字典
[searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
NSString *itemIDString = @“MyPasswordForFtp”;NSData *itemID= [itemIDString dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:itemIDforKey:(id)kSecAttrGeneric];
NSString *account = @“com.mykeychain.ftppassword”;NSString *service = @“com.mykeychain.ftppassword”;
[searchDictionary setObject:account forKey:(id)kSecAttrAccount];
[searchDictionary setObject:service forKey:(id)kSecAttrService];
// 建立更新字典
NSMutableDictionary updateDictionary = [[NSMutableDictionary dictionary];
// 设置要更新的新密码
NSString
newPassword = @“654321”;
NSData *passwordData = [newPassword dataUsingEncoding:NSUTF8StringEncoding]; [updateDictionary setObject:passwordData forKey:(id)kSecValueData];
//进行更新
OSStatus status = SecItemUpdate((CFDictionaryRef)searchDictionary, (CFDictionaryRef)updateDictionary);

keychain接口常见错误SecItemUpdate 返回-50(errSecParam):请检查查询词典里是否存在读取条件,比如kSecReturnData,kSecMatchLimit等SecItemAdd 返回-25299 (errSecDuplicateItem: 请检查kSecAttrAccount和kSecAttrService是否已经存在于keychain中,请尝试设置其他值避免重复官方文档:https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/iPhoneTasks/iPhoneTasks.html#//apple_ref/doc/uid/TP30000897-CH208-SW1https://zhuanlan.zhihu.com/p/22731783http://www.360doc.com/content/15/0708/15/20918780_483580050.shtmlhttp://blog.51cto.com/13619586/2074256https://www.jianshu.com/p/e92e4e4b41a5

作者:X堇色
链接:https://www.jianshu.com/p/eb09b3c881a3
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值