keychain(钥匙串) 提供了一种安全的保存私密信息(密码,序列号,证书等)的方式。即使重新安装程序保存过的密码也不会丢失。
keychain可以安全的记录用户的密码,其中keychain保存的密码文件都是经过加密的,通常情况下即使直接打开这个加密文件也获取不到keychain中的密码。
Apple提供了使用keychain的API,详细可见:Keychain Services Reference
IOS中keychain与NSUserdefaults相比
NSUserdefaults适用于保存轻量级的数据,加载NSUserdefaults中的数据相对要快一些,数据以明文的形式保存在plist文件,所以不适合用来保存密码。文件的位置是Library/Application Support/iPhone Simulator/模拟器版本/Applications/应用对应的数字/Library/Preference/.plist文件
keychain采用的是将数据加密之后再保存到本地的,这样对数据而言有更高的安全性,适合保存密码之类的数据。数据保存的目录是Library/Application Support/iPhone Simulator/模拟器版本/Library/Keychains/
使用方法:
在工程中导入Security.framework
代码:
CHKeychain.h
1: #import <Foundation/Foundation.h>
2: #import <Security/Security.h>
3:
4:
5: @interface CHKeychain : NSObject
6:
7: + (void)save:(NSString *)service data:(id)data;
8: + (id)load:(NSString *)service;
9: + (void)delete:(NSString *)service;
10:
11:
12: @end
CHKeychain.m
1: #import "CHKeychain.h"
2:
3: @implementation CHKeychain
4: + (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
5: return [NSMutableDictionary dictionaryWithObjectsAndKeys:
6: (id)kSecClassGenericPassword,(id)kSecClass,
7: service, (id)kSecAttrService,
8: service, (id)kSecAttrAccount,
9: (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
10: nil];
11: }
12:
13: + (void)save:(NSString *)service data:(id)data {
14: //Get search dictionary
15: NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
16: //Delete old item before add new item
17: SecItemDelete((CFDictionaryRef)keychainQuery);
18: //Add new object to search dictionary(Attention:the data format)
19: [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
20: //Add item to keychain with the search dictionary
21: SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
22: }
23:
24: + (id)load:(NSString *)service {
25: id ret = nil;
26: NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
27: //Configure the search setting
28: //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
29: [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
30: [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
31: CFDataRef keyData = NULL;
32: if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
33: @try {
34: ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData];
35: } @catch (NSException *e) {
36: NSLog(@"Unarchive of %@ failed: %@", service, e);
37: } @finally {
38: }
39: }
40: if (keyData)
41: CFRelease(keyData);
42: return ret;
43: }
44:
45: + (void)delete:(NSString *)service {
46: NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
47: SecItemDelete((CFDictionaryRef)keychainQuery);
48: }
49:
50:
51: @end
1.定义几个字符串用来做key:
1: NSString * const KEY_USERNAME_PASSWORD = @"com.company.app.usernamepassword";
2: NSString * const KEY_USERNAME = @"com.company.app.username";
3: NSString * const KEY_PASSWORD = @"com.company.app.password";
2. 把用户名和密码存入keychain:
1: NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionary];
2: [usernamepasswordKVPairs setObject:txtfldUsername.text forKey:KEY_USERNAME];
3: [usernamepasswordKVPairs setObject:txtfldPassword.text forKey:KEY_PASSWORD];
4: [CHKeychain save:KEY_USERNAME_PASSWORD data:usernamepasswordKVPairs];
3. 从keychain中取出用户名和密码:
1: NSMutableDictionary *usernamepasswordKVPairs = (NSMutableDictionary *)[CHKeychain load:KEY_USERNAME_PASSWORD];
2: txtfldUsername.text = [usernamepasswordKVPairs objectForKey:KEY_USERNAME];
3: txtfldPassword.text = [usernamepasswordKVPairs objectForKey:KEY_PASSWORD];
4. 删除一个keychain item:
1: [CHKeychain delete:KEY_USERNAME_PASSWORD];