jackreichert
jackreichert

Reputation: 1979

How do I encode an unmanaged<SecKey> to base64 to send to another server?

I'm trying to use key pair encryption to validate identity between my app and my PHP server. To do this I need to send the public key over to the server after I generate it in my app.

if let pubKey = NSData(base64EncodedData: publicKey, options: NSDataBase64DecodingOptions.allZeros)! {
    println(pubKey)
}

publicKey is of type Unmanaged<SecKey>.

The error I'm getting in the above code is: Extra argument 'base64EncodedData' in call

How would I do this? Is there a better way?

Edit: This is how the keypair is generated:

var publicKeyPtr, privateKeyPtr: Unmanaged<SecKey>?
let parameters = [
    String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
    String(kSecAttrKeySizeInBits): 2048
]
let result = SecKeyGeneratePair(parameters, &publicKeyPtr, &privateKeyPtr)
let publicKey = publicKeyPtr!.takeRetainedValue()
let privateKey = privateKeyPtr!.takeRetainedValue()
let blockSize = SecKeyGetBlockSize(publicKey)

Edit 2: So the issue is that SecKey is not NSData, so my question here should be: How do I convert a publicKey:SecKey to NSData?

Upvotes: 3

Views: 5255

Answers (3)

Jere
Jere

Reputation: 1

Swift 4 method to get base64 string from SecKey, publicKey :)

guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey!, nil) else {
            NSLog("\tError obtaining export of public key.")
            return ""
        }
        let publicKeyNSData = NSData(data: publicKeyData as Data)
        let publicKeyBase64Str = publicKeyNSData.base64EncodedString()

Upvotes: 0

Raphael
Raphael

Reputation: 10549

While the fact is barely documented, you can pull out everything you need (that is, modulus and exponent) from the SecKey using SecKeyCopyAttributes.

See here for the details.

Upvotes: 0

ThorstenC
ThorstenC

Reputation: 1314

It seems that you can temporary store the key to keychain and then get it back and convert it to data:

func convertSecKeyToBase64(inputKey: SecKey) ->String? {
    // First Temp add to keychain
    let tempTag = "de.a-bundle-id.temp"
    let addParameters :[String:AnyObject] = [
        String(kSecClass): kSecClassKey,
        String(kSecAttrApplicationTag): tempTag,
        String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
        String(kSecValueRef): inputKey,
        String(kSecReturnData):kCFBooleanTrue
    ]

    var keyPtr: Unmanaged<AnyObject>?
    let result = SecItemAdd(addParameters, &keyPtr)
    switch result {
    case noErr:
        let data = keyPtr!.takeRetainedValue() as! NSData

        // Remove from Keychain again:
        SecItemDelete(addParameters)
        let encodingParameter = NSDataBase64EncodingOptions(rawValue: 0)
        return data.base64EncodedStringWithOptions(encodingParameter)

    case errSecDuplicateItem:
        println("Duplicate Item")
        SecItemDelete(addParameters)
        return nil

    case errSecItemNotFound:
        println("Not found!")
        return nil

    default:
        println("Error: \(result)")
        return nil
    }
}

Upvotes: 6

Related Questions