Securing user data with Keychain for iOS
In this post, I’ll discuss securely persisting data in iOS apps using Apple’s Keychain Services. I’ll walk you through what the Keychain Services API does and illustrate a quick and easy way to start using Keychain functionality in your apps through implementation of a wrapper.
Keychain offers a secure alternative to saving sensitive data, such as user names and passwords, with NSUserDefaults, plist or similar methods.
As you might already know, NSUserDefaults is simple and effective for saving small, simple bits of data, like NSNumbers or NSStrings, to your device’s file system. But this data is in no way stored securely as hackers can access it pretty easily from the device.
Apple has provided the Keychain Services API to deal with this problem and help developers build apps that safely handle passwords and other sensitive information.
A keychain is defined in Apple’s documentation as:
“…an encrypted container that securely stores small chunks of data on behalf of apps and secure services.”
and
“…simply a database stored in the file system.”
Keychain is great because data encryption automatically is taken care of before it is stored in the file system so there is no need to waste time building encryption algorithms.
A keychain in both OS and iOS can be configured to lock. When locked it is impossible to access and decrypt stored keychain items. For iOS the keychain is locked when the device is locked and unlocked when the device is unlocked. Even when it is unlocked, only apps that have created an item can access it, unless configured otherwise.
Keychain also offers other features like: accessing keychain items across apps. Normally, an app only has access to items it created but configuration can be made to let it access data within a group of designated apps.
Implementing the Keychain API
Storing and retrieving data directly with Keychain is not an easy task. Unfortunately, the Keychain API is a bit torturous to use. It is written in C and requires a lot of time-consuming configuration. Luckily, Apple and many other contributors have created higher level wrappers to hide the convoluted C code and organization powering things from beneath.
If you would like to see how to use the API directly it seems that this is the best tutorial out there(despite being pretty outdated): Ray Wenderlich’s Basic Security in iOS 5.
This page of Apple’s API reference documentation is also a great way to see how to implement Keychain directly in your app.
Implementation with Wrappers
Apple’s own Keychain wrapper is called GenericKeychain and is available within the sample code in both Objective C and Swift.
Other wrappers exist as Cocoapods or extension libraries on Github and other dependency management sites.
Here are a few Keychain wrappers I recommend:
- SwiftKeychainWrapper by Jason Rendel(jrendel) for Swift. https://cocoapods.org/pods/SwiftKeychainWrapper or https://github.com/jrendel/SwiftKeychainWrapper
- SAMKeychain by Sam Soffes for Objective C. https://cocoapods.org/pods/SAMKeychain
- Locksmith by Matthew Palmer for Swift. (Check out the video tutorial) https://github.com/matthewpalmer/Locksmith
Most wrappers include three methods: one to add a keychain item, one to edit a keychain item, and one to delete it, and make accessing and editing keychain items possible with one line of code.
Step-by-Step: Implement Keychain with a Wrapper
Let’s walk through implementing Keychain for a Swift program with the help of SwiftKeychainWrapper by Jason Rendel.
- Open an Xcode Swift project where you would like to store sensitive data or test out using Keychain.
- Go to the source files for your wrapper. In our case this will be: https://cocoapods.org/pods/SwiftKeychainWrapper and in order to make it easier to stay up-to-date we’ll use a cocoapod. Here you can check out the documentation for the wrapper and see how data will be added as a keychain item, edited and deleted.
In this wrappers’ documentation we can see that it’s recommended usage is saving Strings. So for this example we’ll save a hypothetical password.
3. Make a pod file for your project and add the latest SwiftKeychainWrapper Cocoapod, like this:
Save it and remember to do ‘pod install’ in command line for your project.
4. Open the workspace file for your project.
In an actual application you could receive the sensitive string in various ways, whether it is from a request to a server asking for user name and password or from a textfield where a user will enter the information.
For our example we’ll make this a simple textfield that collects a password string that we want to store in keychain.
Go to storyboard and set up a view controller with a textfield and one button, like this:
Set this view controller to correspond with the view controller class.
Then make an IBOutlet connecting the text field to the view controller and an IBAction connect the button. Your view controller class should look like this:
5. If you remember from above, the method to save a string to keychain with the SwiftKeychainWrapper is:
let saveSuccessful: Bool = KeychainWrapper.standard.set("Some String", forKey: "myKey")
Now let’s implement taking the string value from the passwordTextField, giving it a key, and saving it to keychain when the savePasswordButton is tapped. The method returns a boolean value which acts as a confirmation that the string was successfully saved.
Here is what your code can look like.
Before using the .set method to save to keychain I am doing a check using an ‘if let’ statement to make sure that there is indeed some text in the textfield.
When you enter text and tap the button it appears that nothing happens, but down in the console we can see that it printed a confirmation.
This means the string was saved to Keychain!
6. To retrieve the string from Keychain let’s set up another button.
This button won’t do anything except print the retrieved string to the console.
Connect its IBAction and use the required method retrieve the string. See below.
Add the following code to the retrievePasswordButtonTapped method.
Please note I’ve not set up any checks here to make sure keychain contains any items. You will want to handle this checking in a real app.
When tapping the Retrieve button the submitted password should be retrieved and printed in the console like this:
7. Removing an item from Keychain follows the same pattern using the following method:
let removeSuccessful: Bool = KeychainWrapper.standard.remove(key: "myKey")
8. Now you’ve successfully used the SwiftKeychainWrapper to securely persist and access a string value!
As you can see adding, retrieving, and removing from Keychain with the wrapper are accomplished with one simple line of code.
Each wrapper has it’s own slightly unique syntax and configurable options, but they all, more or less, follow the same pattern as in this example.
Thank you for reading!
Check out the resources for more in depth information.
Resources:
Helpful articles and tutorials:
Awesome tutorial covering the subject in more depth:
Helpful videos: