Error -50 when attempting to store a SymmetricKey in Keychain

Hi all,
I've been working on implementing CryptoKit in my app, and I seem to have run into a wall where I can't get the generated SymmetricKey to be stored in the keychain. Here is the code I've written:

Code Block swift
static func makeAndStoreKey(name: String) throws -> SymmetricKey? {
let nameData = name.data(using: .utf8)
let symmetricKey = SymmetricKey(size: .bits256)
let query = [kSecClass: kSecClassGenericPassword,
kSecAttrApplicationTag: nameData!,
kSecValueRef: symmetricKey.rawRepresentation] as [String: Any]
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else {
throw KeyStoreError("Unable to store item: \(status.message)")
}
return symmetricKey
}
static func loadKey(name: String) throws -> SymmetricKey? {
let nameData = name.data(using: .utf8)
let query = [kSecClass: kSecClassGenericPassword,
kSecAttrApplicationTag: nameData!,
kSecReturnRef: true] as [String: Any]
var item: CFTypeRef?
switch SecItemCopyMatching(query as CFDictionary, &item) {
case errSecSuccess:
guard let data = item as? Data else { return nil }
return SymmetricKey(data: data)
case errSecItemNotFound: return nil
case let status: throw KeyStoreError("Keychain read failed: \(status.message)")
}
}


I was also attempting to add the following attributes to the keychain query (but commented them out because I was attempting to troubleshoot this issue)
Code Block swift
kSecAttrIsPermanent: true,
kSecAttrCanEncrypt: true,
kSecAttrCanDecrypt: true,
kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
kSecUseDataProtectionKeychain: true,
kSecAttrIsInvisible: true,


I've tried storing the key as both a a kSecClassGenericPassword and a kSecClassKey, and it returns the same -50 ("One or more parameters passed to a function were not valid.") error. I've tried storing the key as both Data and the SymmetricKey iteself, and I have tried storing the ApplicationTag as both a String and as Data. Neither of these resolve the issue. I'm hoping someone has some ideas on what I'm missing here.

I've been following the instructions listed here: https://developer.apple.com/documentation/cryptokit/storing_cryptokit_keys_in_the_keychain

Here is my code to convert to a rawRepresentation (the code supplied in the CryptoKit Keys in the Keychain article didn't compile unfortunately).
Code Block swift
import Foundation
import CryptoKit
extension SymmetricKey: GenericPasswordConvertible {
public var description: String {
return ""
}
init<D>(rawRepresentation data: D) throws where D: ContiguousBytes {
self.init(data: data)
}
var rawRepresentation: Data {
var intArr = [UInt8]()
self.withUnsafeBytes { ptr in
intArr.append(contentsOf: ptr)
}
return Data(intArr)
}
}

Thanks in advance for the help.

Accepted Reply

You’re using the wrong attributes on your kSecClassGenericPassword parameter dictionaries. The kSecAttrApplicationTag tag is only supported on kSecClassKey items. The primary attributes for a kSecClassGenericPassword should be kSecAttrService and kSecAttrAccount.

<Security/SecItem.h> has a comprehensive list of which attributes apply to which classes.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

You’re using the wrong attributes on your kSecClassGenericPassword parameter dictionaries. The kSecAttrApplicationTag tag is only supported on kSecClassKey items. The primary attributes for a kSecClassGenericPassword should be kSecAttrService and kSecAttrAccount.

<Security/SecItem.h> has a comprehensive list of which attributes apply to which classes.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"