Search code examples
javaandroidswiftpublic-key-exchange

Im trying to export EC Public keys from android to iOS, what is the best way to do this?


I'm trying to perform an EC key exchange between iOS and Android clients of my app. I have successfully transported and generated them from iOS to Android. But I'm unable to use the keys generated in the android app in iOS.

I'm using the SecKeyCreateWithData method in swift to generate keys from 'Data' type, but I'm getting this error:

Error Domain=NSOSStatusErrorDomain Code=-50 "EC public key creation from data failed"

I used the follwing encoding in the android client, it produces a base64 string which I process and pass as Data SecKeyCreateWithData in swift

byte [] encodedPublicKey = PubKey.getEncoded();
String b64PublicKey = Base64.encodeToString(encodedPublicKey,Base64.DEFAULT);

I'd like to generate a SecKeyRef public key, please help


Solution

  • Apple APIs don't follow the standards exactly to play nicely with other platforms. Exporting an EC public key on iOS doesn't include a fixed header identifier. Therefore, the import functions also expect that the header is missing. This means you must remove the header that Android creates when importing the Android EC key.

    Here's a portable example:

    CFMutableDataRef mutableData = CFDataCreateMutable(kCFAllocatorDefault, 0);
    if (mutableData)
    {
        //Fixed schema header
        const UInt8 headerBytes[] = { 0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,
        0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,
        0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,
            0x42,0x00 };
        const CFIndex headerSize = sizeof(headerBytes);
    
        //Uncomment for exporting (such as via SecKeyCopyExternalRepresentation)
        //CFDataAppendBytes(mutableData, headerBytes, headerSize);
        //CFDataAppendBytes(mutableData, CFDataGetBytePtr(iosKeyData), CFDataGetLength(iosKeyData));
    
        //For importing Android key data
        CFDataAppendBytes(mutableData, CFDataGetBytePtr(androidKeyData), CFDataGetLength(androidKeyData));
        CFDataDeleteBytes(mutableData, CFRangeMake(0, headerSize));
    
        //Use the mutableData here (SecKeyCreateWithData)
    
        CFRelease(mutableData);
    }
    

    Swift version:

        let mutableData = CFDataCreateMutable(kCFAllocatorDefault, CFIndex(0))
        if mutableData != nil 
        {
            //Fixed schema header
            //var headerBytes = [0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00] as [UInt8]
            let headerSize = 26
    
            //Uncomment for exporting (such as via SecKeyCopyExternalRepresentation)
            //CFDataAppendBytes(mutableData, &headerBytes, headerSize)
            //CFDataAppendBytes(mutableData, CFDataGetBytePtr(iosKeyData), CFDataGetLength(iosKeyData))
    
            //For importing Android key data
            CFDataAppendBytes(mutableData, CFDataGetBytePtr(androidKeyData), CFDataGetLength(androidKeyData))
            CFDataDeleteBytes(mutableData, CFRangeMake(CFIndex(0), headerSize))
    
            //Use the mutableData here (SecKeyCreateWithData)
        }