SecKeyCreateRandomKey with EC key type generates broken keypair

Why does the following code generate a public key that can't be parsed by openssl?

import Security
import CryptoKit

func generateKeys() throws -> (privateKey: SecKey, publicKey: SecKey)  {
        let query: [String: Any] = [
            kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
            kSecAttrKeySizeInBits as String: 256,
            kSecAttrIsPermanent as String: false
        ]

        var error: Unmanaged<CFError>?
           
        guard let privateKey = SecKeyCreateRandomKey(query as CFDictionary, &error) else {
            throw error!.takeRetainedValue()
        }
        let publicKey = SecKeyCopyPublicKey(privateKey)!
        return (privateKey, publicKey)

}

extension SecKey {
    func exportBase64EncodedKey() -> String {
        var error: Unmanaged<CFError>?
        guard let data = SecKeyCopyExternalRepresentation(self, &error) else {
            fatalError("Failed to export key: \(error!.takeRetainedValue())")
        }
        return (data as Data).base64EncodedString(options: [.lineLength64Characters])
    }
}


func printPublicKey() {
        let keyPair = try! generateKeys()
        let encodedPublicKey = keyPair.publicKey.exportBase64EncodedKey()
        var header = "-----BEGIN PUBLIC KEY-----"
        var footer = "-----END PUBLIC KEY-----"
        var pemKey = "\(header)\n\(encodedPublicKey)\n\(footer)\n"
        print(pemKey)
}

printPublicKey()

when parsing the key I get this:

openssl pkey -pubin -in new_public_key.pem -text -noout

Could not find private key of Public Key from new_public_key.pem
404278EC01000000:error:1E08010C:DECODER routines:OSSL_DECODER_from_bio:unsupported:crypto/encode_decode/decoder_lib.c:102:No supported data to decode.

Replacing kSecAttrKeyTypeECSECPrimeRandom with kSecAttrKeyTypeRSA and a bigger key size (e.g. 2048) gives me a working public key that can be parsed by Openssl.

Thanks!

Answered by DTS Engineer in 820657022
Why does the following code generate a public key that can't be parsed by openssl?

Because SecKeyCopyExternalRepresentation returns raw key bytes and openssl is expected the key to be wrapped, probably in a SubjectPublicKeyInfo structure. I recommend that you have a read through On Cryptographic Keys Formats.

If your goal is to get a PEM then the easiest option is to feed the raw key bytes in Apple CryptoKit (see here) and then get the pemRepresentation property.

Share and Enjoy

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

Accepted Answer
Why does the following code generate a public key that can't be parsed by openssl?

Because SecKeyCopyExternalRepresentation returns raw key bytes and openssl is expected the key to be wrapped, probably in a SubjectPublicKeyInfo structure. I recommend that you have a read through On Cryptographic Keys Formats.

If your goal is to get a PEM then the easiest option is to feed the raw key bytes in Apple CryptoKit (see here) and then get the pemRepresentation property.

Share and Enjoy

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

SecKeyCreateRandomKey with EC key type generates broken keypair
 
 
Q