How to Create SecKeys from Data and Decrypt?

I am trying to communicate with a Java server over TCP, but I'm having issues trying to make the data secure in transit using RSA and AES. The server creates an AES key, encodes it in utf8, and sends it to the IOS Client, where it should be decoded back into a byte array as a Data object. Then, Using the Cryptokit framework, I try to create a SecKey object from it. I am stumped when trying to do so, though:

func createSecKeyFromAESKeyData(aesKeyData: Data) -> SecKey? {
    // Define the key attributes
    let keyAttributes: [CFString: Any] = [
        kSecAttrKeyClass: kSecAttrKeyClassSymmetric,
        kSecAttrKeySizeInBits: 128,
        kSecAttrIsPermanent: false
    ]
    // Convert the AES key data into a SecKey object
    var error: Unmanaged<CFError>?
    guard let key = SecKeyCreateWithData(aesKeyData as CFData, keyAttributes as CFDictionary, &error) else {
        if let error = error {
            print("Error creating SecKey: \(error.takeRetainedValue() as Error)")
        } else {
            print("Unknown error creating SecKey")
        }
        return nil
    }
    return key
}

Despite setting up my key attribute dictionary with the correct information (AES_128_GCM_SHA256, 128 bits, impermanent) based on how I generate it in the Java code, I keep getting a runtime error at the SecKeyCreateWithData call stating "Unsupported symmetric key type: 4865". I am unsure what this means and how to fix it as there doesn't seem to be any information on it online. If it helps, the Java code is using AES GCM with no padding, and we have confirmed that the data being sent is indeed 128 bits. How can I take this byte array and create a SecKey from it properly so we can pass secure data?

Similarly, I have also tried using RSA encryption for some data, but with this method, I generate the key pair on the iOS client and send the parts of the public key to the Java server where it (seemingly correctly) created the cipher from the passed data. However, trying to send anything encrypted back resulted in "RSAdecrypt wrong input (err -27)" when decrypting:

func decryptAESKey(encryptedKeyData: Data, privateKey: SecKey) -> Data? {
    // Decrypt the received AES key using the private key
    var error: Unmanaged<CFError>?
    guard let decryptedKeyData = SecKeyCreateDecryptedData(privateKey, .rsaEncryptionOAEPSHA256, encryptedKeyData as CFData, &error) as Data? else {
        print("Error decrypting AES key:", error!.takeRetainedValue() as Error)
        return nil
    }
    return decryptedKeyData
}

Any assistance in figuring out how to properly use SecKeys in these ways would be greatly appreciated. Additionally, the relevant Java code can be provided if necessary.

Replies

SecKey does not support symmetric keys [1]. It’s intended to be used for asymmetric keys, like RSA or EC keys.

The only iOS API for working with AES-GCM is the AES.GCM support in Apple CryptoKit.

Share and Enjoy

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

[1] On iOS and its descendents. On macOS the situation is more nuanced, which is why the kSecAttrKeyClassSymmetric constant exists. However, the macOS support relies on old code paths, running through CDSA and the file-based keychain, so it’s best if you just ignore kSecAttrKeyClassSymmetric.