一.基本知识

1.方法

SecItemAdd 增
SecItemUpdate 改
SecItemDelete 删
SecItemCopyMatching 查

2.权限

文档上说iOS的keyChain是一个相对独立的空间,当程序替换,删除时并不会删除keyChain的内容,这个要比Library/Cache好。刷机,恢复出厂应该就没有了。关于备份,只会备份数据,到那时不会备份设备的密钥,换句话说,即使拿到数据,也没有办法解密里面的内容。有人说似乎破解的手机就能破解keyChain,本人并不清楚,希望有大神能指教。但个人认为,keyChain只是沙盒的升级版,可以存放一些非私密的信息,即使破解也不影响其它用户,只影响那个破解了的设备。(比如针对该设备的一个密钥)。

可访问性一般来说,自己的程序只能访问自己的keychain,相同bundle的程序通过设置group可以互相共享同组的keychain,从而实现程序间可以共同访问一些数据。详细后面介绍一些我测试下来的经验。

3.如何查询keyChain

genericPasswordQuery = [[NSMutableDictionary alloc] init];
[genericPasswordQuery setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];//1
[genericPasswordQuery setObject:identifier forKey:(id)kSecAttrGeneric];//2
if (accessGroup != nil){[genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];//3
}
[genericPasswordQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];//4
[genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];//5
NSDictionary *tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery];
NSMutableDictionary *outDictionary = nil;
if (SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef *)&outDictionary) == noErr){//6
//found and outDicitionary is not nil
}else{
//not found
}

1.设置Class值,每个Class对应的都有不同的参数类型

2.用户确定的参数,一般是程序中使用的类别,比如说是"Password"或"Account Info",作为search的主力条件

3.设置Group,如果不同程序都拥有这个组,那么不同程序间可以共享这个组的数据

4.只返回第一个匹配数据,查询方法使用,还有值kSecMatchLimitAll

5.返回数据为CFDicitionaryRef,查询方法使用

6.执行查询方法,判断返回值

eg:这个是none-ARC的代码哦!ARC情况下会有bridge提示。

4.类型转换

介绍增删改方法调用前,先介绍转换方法,如何将NSDictionary转换成KeyChain方法可以设置的Dicitionary,一般在写程序过程中,应该尽量避免直接访问KeyChain,一般会创建一个NSDictionary来同步对应的数据,所以两者需要做转换。

//data to secItem
- (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert
{// Create a dictionary to return populated with the attributes and data.NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];//设置kSecClass[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];//将Dictionary里的kSecValueData(一般就是这个keyChain里主要内容,比如说是password),NSString转换成NSDataNSString *passwordString = [dictionaryToConvert objectForKey:(id)kSecValueData];[returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];return returnDictionary;
}
//secItem to data
- (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert
{NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];// Add the proper search key and class attribute.[returnDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];// Acquire the password data from the attributes.NSData *passwordData = NULL;if (SecItemCopyMatching((CFDictionaryRef)returnDictionary, (CFTypeRef *)&passwordData) == noErr){// 删除多余的kSecReturnData数据[returnDictionary removeObjectForKey:(id)kSecReturnData];// 对应前面的步骤,将数据从NSData转成NSStringNSString *password = [[[NSString alloc] initWithBytes:[passwordData bytes] length:[passwordData length]encoding:NSUTF8StringEncoding] autorelease];[returnDictionary setObject:password forKey:(id)kSecValueData];}else{NSAssert(NO, @"Serious error, no matching item found in the keychain.\n");}[passwordData release]; return returnDictionary;
}

5.增删改

用代码来说明

- (void)writeToKeychain
{NSDictionary *attributes = NULL;NSMutableDictionary *updateItem = NULL;OSStatus result;//判断是增还是改if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) == noErr){// First we need the attributes from the Keychain.updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes];// Second we need to add the appropriate search key/values.[updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];// Lastly, we need to set up the updated attribute list being careful to remove the class.NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData];//删除kSecClass update不能update该字段,否则会报错[tempCheck removeObjectForKey:(id)kSecClass];//参数1表示search的,参数2表示需要更新后的值result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);}else{//增加result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);}
}

删除很简单,就不写注释了

- (void)resetKeychainItem
{OSStatus junk = noErr;if (!keychainItemData){self.keychainItemData = [[NSMutableDictionary alloc] init];}else if (keychainItemData){NSMutableDictionary *tempDictionary = [self dictionaryToSecItemFormat:keychainItemData];junk = SecItemDelete((CFDictionaryRef)tempDictionary);NSAssert( junk == noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary." );}// Default attributes for keychain item.[keychainItemData setObject:@"" forKey:(id)kSecAttrAccount];[keychainItemData setObject:@"" forKey:(id)kSecAttrLabel];[keychainItemData setObject:@"" forKey:(id)kSecAttrDescription];// Default data for keychain item.[keychainItemData setObject:@"" forKey:(id)kSecValueData];
}

二.Group的配置

配置Target的Code Signing Entitlements.

配置该文件

可以配置一个Array列表,表示该程序可以支持多个group

这样就可以在创建secItem时候添加kSecAttrAccessGroup了。

经过测试有以下经验同大家分享:

1.相同bundle下生成的程序都可以共享相同group的keyChain.

相同bundle解释下就是:比如:2个程序分别使用的provision对应bundle是com.jv.key1和com.jv.key2,那你配置文件肯定是{Identifer}.com.jv.{name},其中identifer是苹果生成的随机串号,可以在申请证书时看到,复制过来即可,name可以自己取,程序中指定属于哪个Group即可。

2.如果你在 addkey时,没有指定group,则会默认添加你keychain-access-groups里第一个group,如果你没有设置Entitlements,则默认使用对应的程序的bundle name,比如com.jv.key1,表示只能给自己程序使用。

3.如果你程序添加的group并不存在你的配置文件中,程序会奔溃,表示无法添加。因此你只能添加你配置文件中支持的keychain。

参考资料:

苹果文档:

Keychain Services Reference

Certificate, Key, and Trust Services Programming Guide

Keychain Services Programming Guide

iOS keyChain 研究相关推荐

  1. iOS GPUImage研究总结

    小专栏:GPUImage的源码解读,带你打造一个实用框架 Part one: 关于GPUImage 这里直接引用官方描述: The GPUImage framework is a BSD-licens ...

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

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

  3. iOS GPUImage研究序一:内置滤镜

    本片介绍关于GPUImage的125个内置过滤器:xoxo_x 著 本文参考:https://github.com/BradLarson/GPUImage#gpuimage 颜色调整 GPUImage ...

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

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

  5. html5 ios keychain,iOS Keychain理解

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

  6. iOS KeyChain使用

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

  7. iOS Keychain和keychain share

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

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

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

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

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

最新文章

  1. 深入RESTful无状态原则
  2. leetcode算法题--从尾到头打印链表
  3. linux 隐藏脚本运行,linux – 为什么在运行ls时隐藏此文件?
  4. jaxb 映射 空字段_JAXB和未映射的属性
  5. 第三十五期:当我们在讨论CQRS时,我们在讨论些神马?
  6. java生命小游戏_Java修炼——飞机生存小游戏
  7. 深入理解call、apply、bind(改变函数中的this指向)
  8. 打基础一定要吃透这12类 Python 内置函数
  9. scws sphinx mysql_Sphinx系列文章\SCWS中文分词
  10. win下使用VM虚拟机安装Linux系统
  11. 2019年系统分析师和系统架构师考试经验
  12. 机器学习原理与实践(Python版)
  13. 条件判断结构掷骰子游戏
  14. 鸡蛋,必须放在合适的篮子里
  15. 【Linux】alias及设置
  16. 【揭秘】云服务器1M带宽实际下载速度是多少?
  17. 数据库系统与文件系统的区别
  18. 3984个小时,阿秀亲眼见证:小白非科班学妹 - offer收割机
  19. [转] Scalers:刻意练习的本质就是持续行动+刻意学习
  20. 第1讲--tuxedo总体介绍

热门文章

  1. sim_com AT
  2. Spark随笔(三):straggler的产生原因
  3. MIT6.824 Lab1 MapReduce
  4. 342. 道路与航线
  5. 【开关电源一】电源拓扑之buck、boost、buck-boost
  6. BUCK电源芯片做升压电源的方法(1)
  7. 花狗C语言彩色贪吃蛇(完整代码)
  8. 站群程序-免费站群程序排名
  9. UI设计中聊天气泡框的设计技巧
  10. 面试如何巧妙总结自己的缺点和不足之处呢