kSecClassGenericPassword // A value key representing a non-internet password
kSecClassInternetPassword // A value key representing an internet password
kSecClassCertificate // A value key representing a certificate
kSecClassCertificate // A value key representing a key
kSecClassIdentity // A value key representing an identity, which is a certificate plus a key
iOS stores private information such as passwords, encryption keys, certificates, and identities in a secure storage area called the Keychain. This storage area is managed completely by a co-processor called the Secure Enclave, which is embedded inside the application processor. Because the Keychain is sandboxed on iOS, keychain items may only be retrieved by the application that put them there in the first place.
In some cases you must turn on Keychain Sharing in Xcode capabilities in order to avoid errors.
Because Keychain Services is below the Foundation level, it is restricted to using CoreFoundation types. As a result, most objects are internally represented as CFDictionarys holding CFStrings as their keys and a variety of CoreFoundation types as their values.
While Keychain Services is included as a part of the Security framework, importing Foundation is usually a good option since it includes some helper functions in the backend.
Additionally, if you don't want to deal with Keychain Services directly, Apple provides the Generic Keychain Swift sample project that provides Swift types that use Keychain Services behind the scenes.
Adding a Password to the Keychain
Every Keychain Item is most often represented as a CFDictionary. You can, however, simply use NSDictionary in Objective-C and take advantage of bridging, or in Swift you may use Dictionary and explicitly cast to CFDictionary.
You could construct a password with the following dictionary:
First, you need a key/value pair that lets the Keychain know this is a password. Note that because our dict key is a String we must cast any CFString to a String explicitly in Swift 3. CFString may not be used as the key to a Swift Dictionary because it is not Hashable.
Finally, we need our actual private data. Be sure not to keep this around in memory for too long. This must be CFData.
Finally, the Keychain Services add function wants to know how it should return the newly constructed keychain item. Since you shouldn't be holding on to the data very long in memory, here's how you could only return the attributes:
Now we have constructed our item. Let's add it:
This places the new attributes dict inside result. SecItemAdd takes in the dictionary we constructed, as well as a pointer to where we would like our result. The function then returns an OSStatus indicating success or an error code. Result codes are described here.
Finding a Password in the Keychain
To construct a query, we need to represent it as a CFDictionary. You may also use NSDictionary in Objective-C or Dictionary in Swift and cast to CFDictionary.
We need a class key:
Next, we can specify attributes to narrow down our search:
We can also specify special search modifier keys described here.
Finally, we need to say how we'd like our data returned. Below, we'll request that just the private password itself be returned as a CFData object:
Now, let's search:
Here, SecItemCopyMatching takes in a query dictionary and a pointer to where you'd like the result to go. It returns an OSStatus with a result codes. Here are the possibilities.
Keychain Access Control (TouchID with password fallback)
Keychain allows to save items with special SecAccessControl attribute which will allow to get item from Keychain only after user will be authenticated with Touch ID (or passcode if such fallback is allowed). App is only notified whether the authentication was successful or not, whole UI is managed by iOS.
First, SecAccessControl object should be created:
Next, add it to the dictionary with kSecAttrAccessControl key (which is mutually exclusive with kSecAttrAccessible key you've been using in other examples):
And save it as you've done before:
To access stored data, just query Keychain for a key. Keychain Services will present authentication dialog to the user and return data or nil depending on whether suitable fingerprint was provided or passcode matched.
Optionally, prompt string can be specified:
Pay attention that status will be err if user declined, canceled or failed authorization.
Keychain Add, Update, Remove and Find operations using one file.
Removing a Password from the Keychain
We need only one thing in order to delete an item from the Keychain: a CFDictionary with attributes describing the items to be deleted. Any items that match the query dictionary will be deleted permanently, so if you are only intending to delete a single item be sure to be specific with your query. As always, we can use an NSDictionary in Objective-C or in Swift we can use a Dictionary and then cast to CFDictionary.
A query dictionary, in this context exclusively includes a class key to describe what the item is and attributes to describe information about the item. Inclusion of search restrictions such as kSecMatchCaseInsensitive is not allowed.
And now we can simply remove it:
SecItemDelete returns an OSStatus. Result codes are described here.
Updating a Password in the Keychain
As usual, we first need a CFDictionary to represent the item we want to update. This must contain all of the old values for the item, including the old private data. Then it takes a CFDictionary of any attributes or the data itself that you would like to change.
So first, let's construct a class key and a list of attributes. These attributes can narrow our search but you must include any attributes and there old values if you will be changing them.
Now we must add the old data:
Now let's create the same attributes but a different password:
Now, we just pass it to Keychain Services:
SecItemUpdate returns a status code. Results are described here.
This modified text is an extract of the original Stack Overflow Documentation created by following contributors and released under CC BY-SA 3.0