IOS Keychain instructions

Preface

Keychain Mac we are more familiar with, mainly for some sensitive information such as user name password, use storage, network password, password authentication token, Wi-Fi network, VPN and other credentials. In iOS Keychain, also has the same function, save the information stored in the device, independent of each App. The author of this article outside the sandbox simple finishing in iOS Keychain.

features: 1.. Comparison of NSUserDefault safer to store some data, will be more secure. Even if App
2. is unloaded, stored information still exists, install App again, still can use the information stored is 3.
. The same Team ID development, to achieve a number of App data sharing

A Keychain structure description

The structure of Keychain is composed of key-value.
multiple key-value Tags: show the uniqueness of the
key. When we operate on the Keychain, you can define a dictionary containing the key-value, call API, Keychain
IOS Keychain instructions
operating structure
images: http://www.jianshu.com/p/fa87b6879b99

Two Keychain add / delete / change / check

Given the simple impression of the structure of Keychain, you can manipulate it

The main API OSStatus SecItemAdd * / / * * add (CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result OSStatus SecItemCopyMatching); / * * * / query (CFDictionaryRef query, CFTypeRef __nullable CF_RETURNS_RETAINED result * * * * / OSStatus / update); SecItemUpdate (CFDictionaryRef query, CFDictionaryRef attributesToUpdate); / * * * / OSStatus SecItemDelete (CFDictionaryRef query deleted);

Add / change / * * * / - (IBAction) insertAndUpdate: (ID sender) {/ * *: we need to determine if the keys inside whether there has been added to our key when adding time. If it already exists, we will update it and do not add it, so the two operations are usually written as a function. Key: 1. to check whether there has been the query Dictionary: kSecAttrService, kSecAttrAccount, kSecClass (marked with the stored data is what type of value is kSecClassGenericPassword, on behalf of the general code) 2. add for operation: kSecAttrService, kSecAttrAccount, kSecClass dictionary, kSecValueData 3. update operations (for positioning the dictionary 1 change the key): kSecAttrService, kSecAttrAccount, kSecClass 2 Dictionary (new information) kSecAttrService, kSecAttrAccount, kSecClass, kSecValueData / NSLog (@ "insert:%d", [self addItemWithService:@ "com.tencent" account:@ "Li Lei" password:@ "911"]);} - (BOOL) addItemWithService: (NSString *) service Accou Nt: (NSString * account) password: (NSString * password{) / / the first check whether there has been constructing a dictionary for operation / query NSMutableDictionary *queryDic = [NSMutableDictionary dictionary]; [queryDic setObject:service forKey: (__bridge ID kSecAttrService]); / / [queryDic setObject:account forKey: service label (__bridge ID) kSecAttrAccount] account [queryDic setObject:; / / label (__bridge ID) kSecClassGenericPassword forKey: (__bridge ID kSecClass]); / / that is stored in a password OSStatus status = -1 CFTypeRef; result = NULL; status = SecItemCopyMatching ((__bridge CFDictionaryRef) queryDic, & result); if (status = = errSecItemNotFound) { Add NSData *passwordData = [password / dataUsingEncoding:NSUTF8StringEncoding] not found; / / convert password to NSData [queryDic setObject:passwordData forKey: (__bridge ID kSecValueData]); / / add password status = SecItemAdd ((__bridge CFDictionaryRef) queryDic, NULL); / /!!!!! The key}else if add API (status = = errSecSuccess) {/ / find success. The key that already exists to update NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; / / password convert to NSData NSMutableDictionary *dict [[NSMutableDictionary alloc] [dict s = initWithDictionary:queryDic]; EtObject:passwordData forKey: (__bridge ID kSecValueData]); / / add password status = SecItemUpdate ((__bridge CFDictionaryRef) queryDic (__bridge, CFDictionaryRef) dict); / /!!!! the key update API return} (status = = errSecSuccess);} / * * * / check - (IBAction) select: (ID sender) {/ * * (process: 1. the key to configure a dictionary) operation content: kSecAttrService (attribute), kSecAttrAccount (attributes) of these attributes is to find the or tag based on kSecReturnData (value of @YES indicates that the return type of data (kSecClass), a value of kSecClassGenericPassword indicates the important data for the "general code" type) these restrictions are the result type on the basis of the 2. and then find the API search state and return data (password) 3. if successful it will finally state data (password) into string / NSLog returns (@ "% @" [self, passwordForService:@ "com.tencent" account:@ "Li Lei"]);} / / with native API query password - (NSString *) passwordForService: (nonnull * NSString) service account: (nonnull * NSString) / / account{generates a query with variable NSMutableDictionary *queryDic dictionary] dictionary = [NSMutableDictionary; / / get the password needed to first add search keys and attributes: [queryDic setObject: (__bridge ID) kSecClassGenericPassword forKey: (__bridge ID kSecClass]); / / that general password may be certificates or other things (setObject: [queryDic __bridge ID kCFBooleanTrue forKey: (__bridge ID) kSecReturnData]); / / return Data [que RyDic setObject:service forKey: (__bridge ID kSecAttrService]); / / [queryDic setObject:account forKey: input service (__bridge ID kSecAttrAccount]); / / Account / / input query OSStatus status = -1 CFTypeRef; result = NULL; status = SecItemCopyMatching ((__bridge CFDictionaryRef) queryDic, & result); / / API core to find whether matching and return the password! If (status! = errSecSuccess) {return nil} / / determine the state; / / return data *password = [[NSString / / NSString alloc] initWithData: (__bridge_transfer NSData * result encoding:NSUTF8StringEncoding]); / / string / / kSecReturnData into the delete key; we don't need it: [queryDic removeObjectForKey: (__bridge ID kSecReturnData]); / / will be converted to NSString and password add it to return the dictionary: NSString *password = [[NSString alloc] initWithBytes:[(__bridge_transfer NSData result bytes] length:[(*) __bridge NSData * result length] encoding:NSUTF8StringEncoding] [queryDic); setObject:password forKey: (__bridge ID kSecValueData]); NSLog (@ query:% @ ", queryDic); return password;} / * * * / - delete (IBActi On delete: (ID) NSLog (sender) {@ "delete:%d", [self deleteItemWithService:@ "com.tencent" account:@ "Li Lei"]);} - (BOOL) deleteItemWithService: (NSString * service) account: (NSString * account{) NSMutableDictionary * queryDic = [NSMutableDictionary dictionary]; [queryDic setObject:service forKey: (__bridge ID kSecAttrService]); / / label service [queryDic setObject:account forKey: (__bridge ID kSecAttrAccount]); / / account [queryDic setObject: (__bridge ID label) kSecClassGenericPassword forKey: (__bridge ID kSecClass]); / / that is stored in a password OSStatus status = SecItemDelete (queryDic (CFDictionaryRef)); return (status = = errSecSuccess);}

Reference links: iOS, Keychain, SSKeychain, use the understanding principle

Three Keychain package

Three point one

Explanation: when
authors look for data, they see that most of them are encapsulated in this package. For the source of the method, the author attached the earliest link to time: iOS development – the use of Keychain for password storage

#import "UserInfo.h" @implementation + UserInfo (NSMutableDictionary *) getKeychainQuery: (NSString * service) {return [NSMutableDictionary dictionaryWithObjectsAndKeys: (ID) kSecClassGenericPassword, (ID) kSecClass, service (ID) kSecAttrService, service (ID) kSecAttrAccount, (ID) kSecAttrAccessibleAfterFirstUnlock, (ID) kSecAttrAccessible, nil] #pragma mark;} / / write: the package to add and update the same way, without judgment, directly after the first remove add + (void) save: (NSString *) service data: (ID) data search dictionary NSMutableDictionary {//Get *keychainQuery = [self getKeychainQuery:service]; //Delete old item before add new item SecItemDelete ((CFDictionaryRef) keychainQuery //Add new object to search); Dictionary (Attention:the data format [keychainQuery setObject:[NSKeyedArchiver) archivedDataWithRootObject:data] forKey: (ID) kSecValueData]; //Add item to keychain with the search dictionary SecItemAdd ((CFDictionaryRef) keychainQuery #pragma mark, NULL);} + (ID) load: read (NSString *) service ID {RET = nil; NSMutableDictionary = *keychainQuery [self getKeychainQuery:service]; //Configure the search setting //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 [keychainQuery setObject: (ID) kCFBooleanTrue forKey: (ID) kSecReturnData]; [keychainQuery setObject: (ID) kSecMatchLimitOne forKey: (ID) kSecMatchLimit] CFDataRef; keyData = NULL; if (SecItemCopyMatching ((CFDictionaryRef) keychainQuery (CFTypeRef *) & keyData) = = noErr) {{RET @try = [NSKeyedUnarchiver unarchiveObjectWithData: (__bridge NSData * keyData]);} @catch (NSException *e) {NSLog ("Unarchive of% @ failed: @% @", service, e);}}} @finally {if (keyData) CFRelease (keyData); return ret;} #pragma mark + (void) delete: (delete NSString * service NSMutableDi) { Ctionary *keychainQuery = [self getKeychainQuery:service]; SecItemDelete ((CFDictionaryRef) keychainQuery)} @end
NSString * const @ KEY_USERNAME_PASSWORD = "com.company.app.usernamepassword"; NSString * const @ KEY_USERNAME = "com.company.app.username"; NSString * const @ KEY_PASSWORD = "com.company.app.password"; / / call NSMutableDictionary * userNamePasswordKVPairs = [NSMutableDictionary dictionary]; [userNamePasswordKVPairs setObject:@ forKey:KEY_USERNAME]; [userNamePasswordKVPairs "userName" setObject:@ "password" forKey:KEY_PASSWORD]; NSLog (@ "% @", userNamePasswordKVPairs); / / have KV / / A, username and password will be written to the keychain [UserInfo save:KEY_USERNAME_PASSWORD data:userNamePasswordKVPairs]; / / B, reads the username and password from the keychain NSMutableDictionary *readUsernamePassword = (NSMutableDictionary *) [UserInfo lo Ad:KEY_USERNAME_PASSWORD]; NSString *userName = [readUsernamePassword objectForKey:KEY_USERNAME]; NSString *password = [readUsernamePassword objectForKey:KEY_PASSWORD]; NSLog (username = @% @ ", userName); NSLog (@ password =% @", password); / / C, username and password will be deleted from the keychain [UserInfo delete:KEY_USERNAME_PASSWORD];

Three point two

The package has instructions and demo downloads, and the author does not go into details. Attach a link to the portal: Keychain in iOS, save user name and password

Three point three

Apple official demo instructions, attached link portal: iOS, Keychain, Services, Tasks

Four Keychain three party

Portal: soffes/SAMKeychain

Sharing data between five Keychain App

App for sharing data, the essay has a detailed introduction of the author, no longer
portal: iOS development of the use of keychain and APP share Keychain data for the ID Apple developer said the developers of Membership => Team ID, or you can use the $(AppIdentifierPrefix) can also be replaced with the code acquisition (NSString * bundleSeedID) {NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: kSecClassGenericPassword, kSecClass, bundleSeedID, @ kSecAttrAccount, @ kSecAttrService, (ID), kCFBooleanTrue, kSecReturnAttributes, nil]; CFDictionaryRef result = nil; OSStatus = SecItemCopyMatching (status (CFDictionaryRef) query (CFTypeRef *) & result); if (status = = errSecItemNotFound) status = SecItemAdd ((CFDictionaryRef) query (CFTypeRef *) & result); if (status! = errSecSuccess) return nil; NSString *accessGroup = [(__bridge NSDictionary * result objectForKey:kSecAttrAccessGroup]) NSArray; *components [accessGroup = componentsSeparatedByString:@ “.” NSString *bundleSeedID = [[components; objectEnumerator] nextObject]; CFRelease (result); return bundleSeedID;}

Six Keychain security

Keychain is not very safe, in the jailbreak devices, through some tools easily dump all Keychain data, such as Keychain-Dumper, through the SSH login device, download the keychain_dumper to the /tmp directory, and then chmox +x keychain_dumper
./keychain_dumper &gt to execute permissions directly; keychain_content.txt
, you can view the data corresponding to the data Keychain can iTunes backup, iTunes backup allows users to select whether encrypted backup, not encrypted backup can be restored to any device, and restore the encrypted backup to other devices. Although the ThisDeviceOnly type Item does not backup, but Item backs up the iOS 7, the Keychain data can also span multiple devices via the iCloud synchronization. The default is not synchronized, but by [query setObject: (ID) kCFBooleanTrue forKey: (ID) kSecAttrSynchronizable];
to set the synchronization, synchronization even if set to ThisDeviceOnly, will not take effect in short, taking into account the iCloud server, etc., and even some jailbreak Wi-FI vulnerabilities, may have leaked Keychain data, it is best to encrypted storage link: data storage iOS (three): Keychain Services

Above!