Simple iPhone Keychain Access
Simple iPhone Keychain Access
Mar 29th, 2010 9:14 pm
The keychain is about the only place that an iPhone application can safely store data that will be preserved across a re-installation of the application. Each iPhone application gets its own set of keychain items which are backed up whenever the user backs up the device via iTunes. The backup data is encrypted as part of the backup so that it remains secure even if somebody gets access to the backup data. This makes it very attractive to store sensitive data such as passwords, license keys, etc.
The only problem is that accessing the keychain services is complicated and even the GenericKeychain example code is hard to follow. I hate to include cut and pasted code into my application, especially when I do not understand it. Instead I have gone back to basics to build up a simple iPhone keychain access example that does just what I want and not much more.
In fact all I really want to be able to do is securely store a password string for my application and be able to retrieve it a later date.
Getting Started
A couple of housekeeping items to get started:
- Add the “Security.framework” framework to your iPhone application
- Include the header file <Security/Security.h>
Note that the security framework is a good old fashioned C framework so no Objective-C style methods calls. Also it will only work on the device not in in the iPhone Simulator.
The Basic Search Dictionary
All of the calls to the keychain services make use of a dictionary to define the attributes of the keychain item you want to find, create, update or delete. So the first thing we will do is define a function to allocate and construct this dictionary for us:
static NSString *serviceName = @"com.mycompany.myAppServiceName";
- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
[searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount];
[searchDictionary setObject:serviceName forKey:(id)kSecAttrService];
return searchDictionary;
}
The dictionary contains three items. The first with key kSecClass defines the class of the keychain item we will be dealing with. I want to store a password in the keychain so I use the value kSecClassGenericPassword for the value.
The second item in the dictionary with key kSecAttrGeneric is what we will use to identify the keychain item. It can be any value we choose such as “Password” or “LicenseKey”, etc. To be clear this is not the actual value of the password just a label we will attach to this keychain item so we can find it later. In theory our application could store a number of passwords in the keychain so we need to have a way to identify this particular one from the others. The identifier has to be encoded before being added to the dictionary
The combination of the final two attributes kSecAttrAccount and kSecAttrService should be set to something unique for this keychain. In this example I set the service name to a static string and reuse the identifier as the account name.
You can use multiple attributes for a given class of item. Some of the other attributes that we could also use for the kSecClassGenericPassword item include an account name, description, etc. However by using just a single attribute we can simplify the rest of the code.
Searching the keychain
To find out if our password already exists in the keychain (and what the value of the password is) we use the SecItemCopyMatching function. But first we add a couple of extra items to our basic search dictionary:
- (NSData *)searchKeychainCopyMatching:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
// Add search attributes
[searchDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
// Add search return types
[searchDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
NSData *result = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)searchDictionary,
(CFTypeRef *)&result);
[searchDictionary release];
return result;
}
The first attribute we add to the dictionary is to limit the number of search results that get returned. We are looking for a single entry so we set the attribute kSecMatchLimit to kSecMatchLimitOne.
The next attribute determines how the result is returned. Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue. This means we will get an NSData reference back that we can access directly.
If we were storing and searching for a keychain item with multiple attributes (for example if we were storing an account name and password in the same keychain item) we would need to add the attribute kSecReturnAttributes and the result would be a dictionary of attributes.
Now with the search dictionary set up we call the SecItemCopyMatching function and if our item exists in the keychain the value of the password is returned to in the NSData block. To get the actual decoded string you could do something like:
NSData *passwordData = [self searchKeychainCopyMatching:@"Password"];
if (passwordData) {
NSString *password = [[NSString alloc] initWithData:passwordData
encoding:NSUTF8StringEncoding];
[passwordData release];
}
Creating an item in the keychain
Adding an item is almost the same as the previous examples except that we need to set the value of the password we want to store.
- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:passwordData forKey:(id)kSecValueData];
OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);
[dictionary release];
if (status == errSecSuccess) {
return YES;
}
return NO;
}
To set the value of the password we add the attribute kSecValueData to our search dictionary making sure we encode the string and then call SecItemAdd passing the dictionary as the first argument. If the item already exists in the keychain this will fail.
Updating a keychain item
Updating a keychain is similar to adding an item except that a separate dictionary is used to contain the attributes to be updated. Since in our case we are only updating a single attribute (the password) this is easy:
- (BOOL)updateKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:passwordData forKey:(id)kSecValueData];
OSStatus status = SecItemUpdate((CFDictionaryRef)searchDictionary,
(CFDictionaryRef)updateDictionary);
[searchDictionary release];
[updateDictionary release];
if (status == errSecSuccess) {
return YES;
}
return NO;
}
Deleting an item from the keychain
The final (and easiest) operation is to delete an item from the keychain using the SecItemDelete function and our usual search dictionary:
- (void)deleteKeychainValue:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
SecItemDelete((CFDictionaryRef)searchDictionary);
[searchDictionary release];
}
Simple iPhone Keychain Access的更多相关文章
- Generate a Certificate Signing Request (CSR) in macOS Keychain Access
macOS 10.14 (Mojave) 1. Open the Keychain Access application, located at /Applications/Utilities/Key ...
- Keychain group access
Keychain group access Apr 3, 2010 · 3 minute read · Comments keychain Since iPhone OS 3.0 it has bee ...
- iOS 7.0获取iphone UDID 【转】
iOS 7.0 iOS 7中苹果再一次无情的封杀mac地址,使用之前的方法获取到的mac地址全部都变成了02:00:00:00:00:00.有问题总的解决啊,于是四处查资料,终于有了思路是否可以使用K ...
- 【转】如何使用KeyChain保存和获取UDID
本文是iOS7系列文章第一篇文章,主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题.并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可. 一.iOS ...
- iPhone OS 开发 - 了解并解决代码签名问题
译者:Jestery 发表时间:2010-04-24浏览量:21082评论数:0挑错数:0 了解并解决代码签名问题 (为保持跟开发环境以及APPLE开发者社区网站结构对应,一些名词未作翻译) 绝大多数 ...
- (转)iOS keychain API及其封装
一. Keychain API KeyChain中item的结构为: 1.增加keychain Item OSStatus SecItemAdd (CFDictionaryRef attributes ...
- iPhone应用提交流程:如何将App程序发布到App Store?
对于刚加入iOS应用开发行列的开发者来说,终于经过艰苦的Coding后完成了第一个应用后最重要的历史时刻就是将应用程序提交到iTunes App Store.Xcode 4.2开发工具已经把App提交 ...
- iPhone 真机调试应用程序
原文:http://blog.sina.com.cn/s/blog_68e753f70100r3w5.html 真机调试iphone应用程序 1.真机调试流程概述 1) 真机调试应用程序, ...
- Keychain 浅析
什么是Keychain? 根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌.苹果自己用keychain来保存Wi- ...
随机推荐
- Netty源码分析之Reactor线程模型详解
上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...
- Swift-技巧(八)CVPixelBuffer To CGImage
摘要 Swift 中图像的表现形式不只是 Image,还有更加底层的方式,比如 CVPixelBuffer 像素缓存形式,那么像素缓存转换为可以在应用中展示的 CGImage,就要知道有哪些处理了. ...
- linux 同时执行多个命令及几个基础命令
先后不同的命令用分号:隔开即可 基础命令: 1.cd 进入目录 /代表根目录,.代表当前目录,..代表上一级目录 2.ls 显示当前目录下的所有文件和文件夹 -F区分目录和文件,文件后边是*代表可执行 ...
- AtCoder Grand Contest 055 题解
A 赛时直到最后 10min 才做出这个 A 题,之前猜了一个结论一直没敢写,本来不抱啥希望 AC 的结果比赛结束时交了一发竟然 A 了,由此可见我的水平之菜/dk 考虑每次取出字符串开头字符,不妨设 ...
- Codeforces 1455G - Forbidden Value(map 启发式合并+DP)
Codeforces 题面传送门 & 洛谷题面传送门 首先这个 if 与 end 配对的结构显然形成一个树形结构,考虑把这棵树建出来,于是这个程序的结构就变为,对树进行一遍 DFS,到达某个节 ...
- 【机器学习与R语言】9- 支持向量机
目录 1.理解支持向量机(SVM) 1)SVM特点 2)用超平面分类 3)对非线性空间使用核函数 2. 支持向量机应用示例 1)收集数据 2)探索和准备数据 3)训练数据 4)评估模型 5)提高性能 ...
- RNA_seq 热图绘制
若已经拿到表达矩阵exprSet 若差异较大,进行log缩小不同样本的差距 1.热图全体 1 ##加载包 2 library(pheatmap) 3 4 ##缩小表达量差距 5 exprSet < ...
- keyboard-interactive authentication with the ssh2 server failed 的SecureCRT报错解决
两种解决方法: 一.选定SSH2,选择Authentication,勾选Password,然后将该选项上移,挪到第一位即可 或者: 二.服务器端修改配置 默认情况/etc/ssh/sshd_confi ...
- 搭建zabbix服务器常见问题解析处理
1. 找不到url 2. 服务器无法处理当前请求,PHP解析出错 3. 服务器无法处理当前请求,权限不足 1. 找不到url 浏览器报错:The requested URL /zabbix/ was ...
- 前端3 — js — BOM没完( 不了解也行 )
1.js是什么? -- 英文全称javascript javaScript(简称"JS") 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言.虽然它是作为开发Web页面的脚 ...