Search code examples
iosswiftsecuritykeychainpublic-key

How to get public key in DER format from key stored in iOS keychain?


I am creating key using following code

let tag = "com.example.keys.mykey".data(using: .utf8)!
let attributes: [String: Any] =
[kSecAttrKeyType as String:            kSecAttrKeyTypeECSECPrimeRandom,
 kSecAttrKeySizeInBits as String:      256,
 kSecPrivateKeyAttrs as String:
    [kSecAttrIsPermanent as String:    true,
     kSecAttrApplicationTag as String: tag]]
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error}

Getting public key using

let publicKey = SecKeyCopyPublicKey(privateKey)

Solution

  •  func addDerKeyInfo(rawPublicKey:[UInt8]) -> [UInt8] {
        let DerHdrSubjPubKeyInfo:[UInt8]=[
            /* Ref: RFC 5480 - SubjectPublicKeyInfo's ASN encoded header */
            0x30, 0x59, /* SEQUENCE */
            0x30, 0x13, /* SEQUENCE */
            0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, /* oid: 1.2.840.10045.2.1   */
            0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, /* oid: 1.2.840.10045.3.1.7 */
            0x03, 0x42, /* BITSTRING */
            0x00 /* unused number of bits in bitstring, followed by raw public-key bits */]
        let derKeyInfo = DerHdrSubjPubKeyInfo + rawPublicKey
        return derKeyInfo
    }
    
    func convertbase64StringToByteArray(base64String: String) -> [UInt8] {
        if let nsdata = NSData(base64Encoded: base64String, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)  {
            var bytes = [UInt8](repeating: 0, count: nsdata.length)
            nsdata.getBytes(&bytes,length: nsdata.length)
            return bytes
        }
        else
        {
            print("Invalid base64 String")
        }
    }
    func convertSecKeyToDerKeyFormat(publicKey:SecKey) throws -> String
    {
        do
        {
            if let externalRepresentationOfPublicKey = SecKeyCopyExternalRepresentation(publicKey,&error)
            {
                let derKeyFormat = externalRepresentationOfPublicKey as Data
                var publicKeyByteArray = try convertbase64StringToByteArray(base64String: derKeyFormat.base64EncodedString())
                publicKeyByteArray =  addDerKeyInfo(rawPublicKey: publicKeyByteArray)
                let base64EncodedPublicKey:String=Data(publicKeyByteArray).base64EncodedString()
                return base64EncodedPublicKey
            }
            else
            {
                throw error as! Error
            }
        }
        catch
        {
            throw error
        }
    }
    

    Call convertSecKeyToDerKeyFormat function by passing public key to it.