Hello all, I'm developing IOS Push Notification。 I'll need to generate an AES key and register the key to another backend service so they can encrypt the notification payload using AES-256 cryptography. But based on the official Apple Developer doc (https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/generating_new_cryptographic_keys#2863927), I didn't find a way to generate such a symmetric encryption key. All I found is how to create an asymmetric one. Has Anybody created an AES key in swift before? Your help is much appreciated
How to generate an AES key in swift
Apple specifically recommends AES-GCM, which is why it’s directly supported by Apple CryptoKit.
If you need to do other AES operations, you have to use Common Crypto. A good place to start here is the CCCrypt
man page.
WARNING Calling Common Crypto from Swift is a bit tricky. There is a lot of really bad code snippets out there. I encourage you to look for snippets posted by me here on DevForums (like this). If you have follow-up questions, post ’em here.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Thanks for answering! Based on our guideline, we are supposed to use AES-CBC for encryption. And I generated a random 256-bits symmetric key to achieve this. (Please find the code snippets below.) I have a question here - how can I store such a symmetric key into keychain? Thanks!
internal func generateSymmetricEncryptionKey() throws -> String {
var keyData = Data(count: 32)
let result = keyData.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, 32, $0.baseAddress!)
}
guard result == errSecSuccess else {
throw error
}
return keyData.base64EncodedString()
}
how can I store such a symmetric key into keychain?
On iOS [1] this has a straightforward answer: Store your key in the keychain as a generic password. See Adding a Password to the Keychain.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] On macOS keychains the story is much more nuanced. See On Mac Keychains for the background to this.
Thanks so much. I wrote the below two methods to create and read keys. Another small question - is it possible to store/get the specific creation time of the key generated when reading the key from the keychain?
internal func generateAndStoreSymmetricKey(withKeychainTag: String) throws {
// Parameter:
let alias = withKeychainTag
let key = SymmetricKey(size: .bits256)
let addQuery:[CFString:Any] = [
kSecClass: kSecClassGenericPassword,
kSecAttrLabel: alias,
kSecAttrAccount: "Account \(alias)",
kSecAttrService: "Service \(alias)",
kSecReturnAttributes: true,
kSecValueData: key.rawRepresentation
]
var result: CFTypeRef?
let status = SecItemAdd(addQuery as CFDictionary, &result)
guard status == errSecSuccess else {
throw Error.client("Failed to insert symmetric key into keychain: \(withKeychainTag)")
}
}
internal func retrieveSymmetricKey(withKeychainTag: String) throws -> SymmetricKey? {
// Parameter:
let alias = withKeychainTag
// Seek a generic password with the given account.
let query = [kSecClass: kSecClassGenericPassword,
kSecAttrAccount: "Account \(alias)",
kSecUseDataProtectionKeychain: true,
kSecReturnData: true] as [String: Any]
// Find and cast the result as data.
var item: CFTypeRef?
switch SecItemCopyMatching(query as CFDictionary, &item) {
case errSecSuccess:
guard let data = item as? Data else { throw Error.client("Fail to convert the key reference to Data.") }
return try SymmetricKey(rawRepresentation: data) // Convert back to a key.
case errSecItemNotFound: return nil
default: throw Error("Error in reading the key")
}
}
is it possible to store/get the specific creation time of the key generated when reading the key from the keychain?
Generic passwords support the kSecAttrCreationDate
and kSecAttrModificationDate
attributes. Honestly, I’ve never used these but, given that they’re read-only attributes, they should be populated automatically by the system.
If you want to get this value along with the key’s data, modify your retrieveSymmetricKey(withKeychainTag:)
method to set both kSecReturnData
and kSecReturnAttributes
. The item
value then comes back as a dictionary of attributes. That dictionary also includes the key’s data, accessible using the kSecValueData
key.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"