首先使用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
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

IOS keychain 使用相关推荐

  1. ios keychain 不被清理_iOS签名机制和说明文件【ios企业签名吧】

    IOS签名机制和配置文件.iOS签名机制的作用:保证安装在手机上的应用程序经苹果公式验证和许可.无论是真机调试还是发布App,开发人员都必须经过一些复杂的步骤.以下广州贝壳技术将详细说明. 贝壳科技( ...

  2. iOS keyChain 研究

    一.基本知识 1.方法 SecItemAdd 增 SecItemUpdate 改 SecItemDelete 删 SecItemCopyMatching 查 2.权限 文档上说iOS的keyChain ...

  3. iOS Keychain(钥匙串)原理及使用

    Keychain介绍 Keychain Services 是 macOS 和 iOS 都提供一种安全的存储敏感信息的工具,比如,网络密码:用户访问服务器或者网站,通用密码:用来保存应用程序或者数据库密 ...

  4. html5 ios keychain,iOS Keychain理解

    Keychain 介绍 Keychain Services 是 OS X 和 iOS 都提供一种安全地存储敏感信息的工具,比如,存储用户ID,密码,和证书等.存储这些信息可以免除用户重复输入用户名和密 ...

  5. iOS KeyChain使用

    最近项目需要存储用户的唯一标识符,但是由于如果用户重装APP,获取到的又会是一个新的UDID.查询了一系列资料下来,可以用Keychain进行存储UDID,然后就算重装了APP,也能从Keychain ...

  6. iOS Keychain和keychain share

    一.keychain介绍(摘抄别人的https://blog.hudongdong.com/ios/356.html) 根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不 ...

  7. html5 ios keychain,iOS 用keychain钥匙串保存账号、设备UUID及APP间共享

    iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储.相对于NSUserDefaults.文件保存等一般方式,key ...

  8. html5 ios keychain,iOS10适配之Keychain读写失败

    Keychain iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌,UUID等 Bug 升级正式版Xcode8 运行了下最近的项目 ...

  9. IOS KeyChain

    转自http://my.oschina.net/w11h22j33/blog/206713 一.Keychain 基础 根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不 ...

  10. iOS Keychain钥匙串应用间数据共享

    在一个公司中可能有多款产品.对于用户而言,一般使用一个帐号就可以登陆访问该公司的所有的产品.对于这种情况,如果一款手机中装了该公司的两款(或多款)产品,那么我们希望只在其中一款产品中登陆,那么另一款产 ...

最新文章

  1. APUE读书笔记-09进程关系(04)
  2. Java--Servlet,@ServletSecurity,role,username,password
  3. 如何处理请求返回的二进制数据流转化成xlsx文件?
  4. Node --- Basic认证
  5. python统计字符串中字母个数字母无视大小写_判断一个字符串中字母的个数(无视大小写)...
  6. BZOJ 1012 单调队列+二分
  7. MAC地址和IP地址的关系
  8. python编程书籍1020python编程书籍_从零单排之玩转Python安全编程(II)
  9. java的迭代器类中有哪些类_java中的集合类 以及 迭代器
  10. jQtouch 初体验
  11. ThinkPHP空操作及命名空间
  12. 实际应用中installshield的事件处理
  13. linux内核奇遇记之md源代码解读之七阵列同步一
  14. 解决IIS 下ASP程序错误只显示500,不显示具体错误描述的问题!
  15. Github的安装和使用
  16. 【Sql Server 数据导出】导出篇-Sql Server 2008导出数据至wps
  17. 可微信打印的共享服务器哪好,基于微信的图片打印分享平台
  18. iPhone、iPad屏幕分辨率尺寸对比
  19. 从头来过教你PHP脚本语言(先导篇)
  20. html上上上级目录,html如何表示上级目录

热门文章

  1. android 剪贴板管理器,Clipper一个强大的剪贴板管理器为Android | MOS86
  2. 木曜日威胁情报: 针对学术界的攻击行动和Kelihos僵尸网络之谢幕
  3. Arduino模拟电脑键盘(基于AVR-USB的USB-HID设备)
  4. canvas水平垂直居中
  5. 【计算机视觉】数字图像处理(六)—— 图像压缩
  6. ios label文字行间距_iOS 设置label的行间距教程
  7. 用C语言计算水分子的个数
  8. Python绘制图片一
  9. 对抗样本学习笔记:Adversarial Examples: Attacks and Defenses for Deep Learning
  10. The class file xxx contains a signature 'xxx;' ill-formed at position 6 问题的解决