Store AES key to KeyChain

I was wondering what the correct way is to store an AES key to the KeyChain. I have read articles about people losing key data and also about people not having access to keys.


I know there is an API available to do AES encryption for you, but I want to have direct access to the key data, I just have to. I have seen objective-C implementation using CSSM_ALGID_AES, but that variable is not available in Swift. Furthermore, the documentation says that the kSecAttrKeyTypeAES is not available (or at least no longer) available on iOS.


I managed to create a key dictionary that will create a key as if it is an AES key, as the CSSM_ALGID_AES value equals 2147483649, meaning, I am able to create a key with that type and it is added correctly (read more, correctly might not be correctly).

let aesKey: [String: Any] = [
    String(kSecClass): kSecClassKey,
    String(kSecAttrKeyType): 2147483649,
    String(kSecAttrKeySizeInBits): 128,
    String(kSecAttrEffectiveKeySize): 128,
    String(kSecAttrCanEncrypt): true,
    String(kSecAttrCanDecrypt): true,
    String(kSecAttrCanDerive): false,
    String(kSecAttrCanSign): false,
    String(kSecAttrCanVerify): false,
    String(kSecAttrCanWrap): false,
    String(kSecAttrCanUnwrap): false,
    String(kSecValueData): "1234567887654321".data(using: .utf8)!
]

var result: CFTypeRef? = nil
let status = SecItemAdd(aesKey as CFDictionary, &result)
if status != errSecSuccess {
    print("Error occured during key add: \(status)")
} else {
    print("Created key!")
    print(result ?? "Still no result though")
}


It is interesting to see that this is one working way to store an AES key, however, I am never able to retrieve the SecKeyRef (it also appears it's not created when calling SecItemAdd).


So, is this the correct way to store a key like this, or am I better of creating a kSecClassGenericPassword (as it appears to have the same effect).

Is it also correct to create a key with the kSecAttrKeyType value set to 2147483649, or am I really only allowed to create it with the predefined kSecAttrKeyTypes (EC, ECSECPrimeRandom, RSA).

Are there any other consequences to creating and storing a key like this, like losing access or key data?

Accepted Answer

The advantage of storing keys in items of type

kSecClassKey
is that you can avoid ever loading the key data into your address space. The key data is held by the system and only accessible to system processes. When you do crypto operations on that key, there’s an IPC to the system process, which does the crypto operation, and passes you back the results. This has a bunch of advantages. For example:
  • On both iOS (and macOS with Touch ID), you can store a key in the Secure Enclave and it can’t escape from there.

  • On macOS the key can come from a hardware token and, again, it can’t escape.

  • On macOS, with a file-based keychain, the data is store in the keychain and only directly accessible by the security daemon.

However, all of this only applies to asymmetric keys, for one very good reason. Many crypto algorithms generate a random symmetric key and use that for bulk encryption, and then protect that symmetric key using an asymmetric key. Thus the asymmetric key is only used for small crypto operations, typically less than a 1 KiB. That makes the IPC I discussed above feasible. In contrast, doing that IPC for the symmetric key isn’t really feasible because it would involve transporting the bulk data. This is why our APIs for symmetric encryption, like CommonCrypto, require you to pass in a pointer to a blob of bytes holding the key.

The above is a very roundabout way of saying that we don’t normally store AES keys as

kSecClassKey
. You can do this on macOS if you want to — assuming you’re talking to the file-based keychain — but you can’t do it on iOS or on macOS when talking to the databased keychain. This is why
kSecAttrKeyTypeAES
is not available in the iOS SDK.

The alternative is, as you’ve noted, to use

kSecClassGenericPassword
. That works well in all environments, and it’s what I’d do.

So, to summarise:

  • It is acceptable to store AES keys in a

    kSecClassKey
    item on macOS, but only when talking to the file-based keychain. Use the symbolic constant
    kSecAttrKeyTypeAES
    in this case.
  • It is not acceptable to do this on iOS. Hard coding 2147483649 as an equivalent to

    kSecAttrKeyTypeAES
    is not OK.
  • Likewise on macOS, when talking to the database keychain.

  • In the previous two cases, we recommend that you use

    kSecClassGenericPassword
    .
  • You can also use

    kSecClassGenericPassword
    for the first case, because
    kSecClassKey
    doesn’t really buy you anything.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Store AES key to KeyChain
 
 
Q