Store and access cryptographic keys in the keychain.
The keychain is the best place to store small secrets, like passwords and cryptographic keys. You use the functions of the keychain services API to add, retrieve, delete, or modify keychain items.
Create a Query Dictionary
When you generate keys yourself, as described in Generating New Cryptographic Keys, you can store them in the keychain as an implicit part of that process. If you obtain a key by some other means, you can still store it in the keychain. To do this, begin by creating a query dictionary containing and describing the item:
This query dictionary uses the
k value for the
k entry to indicate a key item (as opposed to a certificate, identity, or password). You also apply an application tag that lets you distinguish the key from others when later searching for it.
Store the Item
Sec function to actually store the item:
Retrieve the Item
When you want to retrieve the key, you construct another query dictionary using the same application tag:
The above dictionary indicates that the key should be of type
k, as in Creating an Asymmetric Key Pair, and that it should have the tag used in that example and above. The last line says that the retrieval should return a key reference (as opposed, for example, to the actual key data).
You use this query with the
Sec function to execute a search and populate an empty reference that you supply:
If the call is successful, as indicated by the status result, you can then use the returned key reference to carry out cryptographic operations. In Objective-C, after you’re done with any keys that you retrieve this way, you’re responsible for freeing their memory. In Swift, the system manages the object’s memory.
Refine the Search
The query in the example above doesn’t restrict the search to a particular key class (public, private, or symmetric) or to any other key characteristic. It matches only for tag and type, returning a reference to the first successful match. Unless you use unique tags for all of your keys of a given type, you might not get the key you were looking for when you run the search. That's because only the first key that matches is returned, and that may or may not be the one you wanted.
There are several ways to deal with this. For example, you can:
Widen the search. If you add the
kentry to the query dictionary with a value of
Sec Match Limit
k, instead of a single key reference,
Sec Match Limit All
Secproduces an array of key references, which you can inspect to find the key of interest.
Item Copy Matching(_: _:)
Narrow the search. If you have other attributes that distinguish your keys, such as key size or key class, add the corresponding entries to the query dictionary before conducting the search.
Avoid reusing tags in the first place. Before adding a key with a given tag and type (or whatever other distinguishing characteristic you have), read existing keys from the keychain with those same characteristics. If you find a potential duplicate, either reuse the original key and skip creating a new one, create the new key using a different tag, or delete the old key using the
Secfunction before adding a new one.