iOS keyChain 研究
一.基本知识
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 研究相关推荐
- iOS GPUImage研究总结
小专栏:GPUImage的源码解读,带你打造一个实用框架 Part one: 关于GPUImage 这里直接引用官方描述: The GPUImage framework is a BSD-licens ...
- ios keychain 不被清理_iOS签名机制和说明文件【ios企业签名吧】
IOS签名机制和配置文件.iOS签名机制的作用:保证安装在手机上的应用程序经苹果公式验证和许可.无论是真机调试还是发布App,开发人员都必须经过一些复杂的步骤.以下广州贝壳技术将详细说明. 贝壳科技( ...
- iOS GPUImage研究序一:内置滤镜
本片介绍关于GPUImage的125个内置过滤器:xoxo_x 著 本文参考:https://github.com/BradLarson/GPUImage#gpuimage 颜色调整 GPUImage ...
- iOS Keychain(钥匙串)原理及使用
Keychain介绍 Keychain Services 是 macOS 和 iOS 都提供一种安全的存储敏感信息的工具,比如,网络密码:用户访问服务器或者网站,通用密码:用来保存应用程序或者数据库密 ...
- html5 ios keychain,iOS Keychain理解
Keychain 介绍 Keychain Services 是 OS X 和 iOS 都提供一种安全地存储敏感信息的工具,比如,存储用户ID,密码,和证书等.存储这些信息可以免除用户重复输入用户名和密 ...
- iOS KeyChain使用
最近项目需要存储用户的唯一标识符,但是由于如果用户重装APP,获取到的又会是一个新的UDID.查询了一系列资料下来,可以用Keychain进行存储UDID,然后就算重装了APP,也能从Keychain ...
- iOS Keychain和keychain share
一.keychain介绍(摘抄别人的https://blog.hudongdong.com/ios/356.html) 根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不 ...
- html5 ios keychain,iOS 用keychain钥匙串保存账号、设备UUID及APP间共享
iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储.相对于NSUserDefaults.文件保存等一般方式,key ...
- html5 ios keychain,iOS10适配之Keychain读写失败
Keychain iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌,UUID等 Bug 升级正式版Xcode8 运行了下最近的项目 ...
最新文章
- 深入RESTful无状态原则
- leetcode算法题--从尾到头打印链表
- linux 隐藏脚本运行,linux – 为什么在运行ls时隐藏此文件?
- jaxb 映射 空字段_JAXB和未映射的属性
- 第三十五期:当我们在讨论CQRS时,我们在讨论些神马?
- java生命小游戏_Java修炼——飞机生存小游戏
- 深入理解call、apply、bind(改变函数中的this指向)
- 打基础一定要吃透这12类 Python 内置函数
- scws sphinx mysql_Sphinx系列文章\SCWS中文分词
- win下使用VM虚拟机安装Linux系统
- 2019年系统分析师和系统架构师考试经验
- 机器学习原理与实践(Python版)
- 条件判断结构掷骰子游戏
- 鸡蛋,必须放在合适的篮子里
- 【Linux】alias及设置
- 【揭秘】云服务器1M带宽实际下载速度是多少?
- 数据库系统与文件系统的区别
- 3984个小时,阿秀亲眼见证:小白非科班学妹 - offer收割机
- [转] Scalers:刻意练习的本质就是持续行动+刻意学习
- 第1讲--tuxedo总体介绍