A glimpse into the iOS Keychain

Radu Dan
4 min readMay 29, 2019

--

Motivation

Ever wanted to store some information in a place where is secure? Maybe you heard that UserDefaults, CoreData are not that great in storing sensitive data, such as passwords, being more vulnerable to attackers.

What about a special place in your device called Keychain?! By special place we mean an encrypted database where you can put users data.

Each application on an iOS device have access to a single keychain. If you build an app you have access to your own items or those that are shared with a group which the app belongs to.

You are not limited storing just passwords. You can put in the keychain secrets, keys, credit card information or notes.

In this article we will explore some parts of the Keychain Services API and see how to store sensitive data like passwords or secrets.

If you want a simple wrapper to the Keychain, viewed as a key-value storage, I created a framework that you can use:
https://github.com/radude89/KeychainStorage.
You can install it via CocoaPods, manually or through Carthage.

Security framework

To access the Keychain you will need to import the Security framework. It offers you capabilities of authorising and authenticating users, storing and retrieving secure data, code signing services and lower level cryptographic functions.

Using Security Framework to secure your sensitive data

Storing data

Let’s see an example:

The data you want to save will be packaged as a keychain item. It will have attached some attributes to control the accessibility and to make it retrievable.

Storing data using Keychain Services API

Let’s see next what you will need to do to store a simple password in the keychain.

Transform the value to Data

Define the query attributes

A query attributes is a dictionary of [String: Any] key value pairs.
For our example, as a minimum way you can specify the service and the class:

  • kSecAttrService: used for generic passwords, represents the item’s service, such as a label.
  • kSecAttrAccount: attribute specific to Internet and generic passwords and defines the item’s account name.
  • kSecClass: defines the value type of the item you want to save.
    It can be a:
  • generic password item (kSecClassGenericPassword)
  • Internet password item (kSecClassInternetPassword)
  • certificate item (kSecClassCertificate)
  • cryptographic key item (kSecClassKey)
  • identity item (kSecClassIdentity)

Add the value

You add the data object in the query dictionary, setting it to kSecValueData key. The item data object is cast from Swift.Data to a CFDataRef, a reference to an immutable CFData object.

You might spotted again CF in as CFDictionary.
CF stands for CoreFoundation and is part of a low-level framework bridged with Swift’s Foundation framework. It is implemented in C language.

The item is added with the function SecItemAdd which returns an OSStatus. You usually verify the status if is of type success.

Retrieving data

Again, let’s use an example to see how we retrieve our previously saved password:

Define the query attributes

In our example we used the following attributes:

  • kSecAttrService: same service as we used for storing the password
  • kSecClass: using generic password items
  • kSecAttrAccount: item’s account name
  • kSecMatchLimit: it can be either kSecMatchLimitOne where a value will correspond to exactly one item or kSecMatchLimitAll where a value will correspond to an unlimited number of items
  • kSecReturnData: if set to yes, the item data will be returned
  • kSecReturnAttributes: if set to yes, it will return the item’s attributes

Retrieve the value

For retrieving the value, we use the function SecItemCopyMatching.

The result object is an optional UnsafeMutablePointer<CFTypeRef?> which is cast to a Swift Dictionary.
The actual data will be retrieved by getting the value found at kSecValueData key.

In Swift 5, UnsafeMutablePointer is a struct having a generic type Pointee. It is used to access data of Pointee type in memory (in our case CFTypeRef). We don’t have an automated memory management, so we should be careful when using this kind of objects.

CFTypeRef gives a generic reference to any Core Foundation objects.

typealias CFTypeRef = AnyObject
// Or:
typedef const CF_BRIDGED_TYPE(id) void * CFTypeRef;

Deleting data

For deleting an item you can write something like:

We use the SecItemDelete function that can delete one or more items if it matches the criteria.

Conclusion

We saw together some basic operations that you can do with Keychain Services API, such as store items, retrieve and delete passwords.
You can check my open source project on GitHub: https://github.com/radude89/KeychainStorage for more examples.

You can find me on Twitter @radude89 or on GitHub: radude89 .

This article can also be found here.

References

--

--