Seckey from public key string from server in Swift
Asked Answered
C

3

9

I want to encrypt data using RSA , I tried to generate the key in my code and it's working , But what I actually need is to get the public key as a string from server and then use it as Seckey so I can use it to encrypt data using RSA, I tried this code:

//KeyString is the string of the key from server
let KeyData = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!


    var cert : Unmanaged<SecCertificateRef>!;
    var  policy : Unmanaged<SecPolicy>!;
    cert = SecCertificateCreateWithData(kCFAllocatorDefault, KeyData);
    policy = SecPolicyCreateBasicX509();
    var status : OSStatus = noErr
    var trust: SecTrust?
    var certArray : [Unmanaged<SecCertificateRef>!] = [cert];
    var certArrayPointer = UnsafeMutablePointer<UnsafePointer<Void>>(certArray)
    status = SecTrustCreateWithCertificates(cert, policy, trust);
    let publicKey: SecKeyRef = SecTrustCopyPublicKey(trust!).takeUnretainedValue()

I couldn't run this code because SecTrustCreateWithCertificates Method is expecting certificate as anyObject! , I don't Know how to fix this,And if solving this will let me get the SecKey.

I got the code above from this answer in objective-c

So if any one can help me getting the right code to solve this , I will be very thankful :)

Craps answered 2/3, 2015 at 10:59 Comment(0)
D
17

For mac:

let pubKey = "-----BEGIN PUBLIC KEY-----MIICIjANBgAgK.......InbFk1FkucQqruMyUCAwEAAQ==-----END PUBLIC KEY-----"
let pubKeyData = pubKey.dataUsingEncoding(NSASCIIStringEncoding)
var error: Unmanaged<CFErrorRef>?
let secKey = SecKeyCreateFromData(NSDictionary(), pubKeyData!, &error)

Where pubKey is a string representation of your public key. If you don't know your public key, you can infer it from your private key with the following command:

openssl rsa -in server.key -pubout  > mykey.pub

Where server.key is the file containing -----BEGIN RSA PRIVATE KEY----- as the first line.

For iOS:

It's a bit more complicate. You need a der file. It's a binary representation of your certificate. If you need to convert an existing certificate, you can do so with the following command:

 openssl x509 -outform der -in file.crt|pem -out mycert.der

The .crt or .pem file contains -----BEGIN CERTIFICATE----- as the first line.

Put the der file in your bundle and do:

let certificateData = NSData(contentsOfURL:NSBundle.mainBundle().URLForResource("mycert", withExtension: "der")!)

let certificate = SecCertificateCreateWithData(nil, certificateData!)

var trust: SecTrustRef?

let policy = SecPolicyCreateBasicX509()
let status = SecTrustCreateWithCertificates(certificate!, policy, &trust)

if status == errSecSuccess {
    let key = SecTrustCopyPublicKey(trust!)!;
}

Yatta ! Key now contains a SecKey representation of your public key. Happy Pinning.

Deirdredeism answered 8/12, 2015 at 13:24 Comment(7)
An explanation of pubKey would make the answer much more useful.Hill
@Hill I edited the answer and added all the process I needed to go through to get that the SecKey; I'm not sure what more can I say about what is a public key without explaining the whole Certificate/RSA thing...Deirdredeism
Thanks for adding the information, it really helps the answer.Hill
Useful commands : Convert .cer to .pem openssl x509 -in NAME.cer -inform der -out NAME.pem Convert .pem to .der openssl x509 -outform der -in NAME.pem -out NAME.derIolenta
Does that mean we must use der file only, cannot use pem key in iOS?Cofer
This doesn't answer the question 'SecKey from public key string sent from the server'Exarate
You can use the PEM key, but you have to strip the header and the footer, and decode the base64 string using Data(base64Encoded: base64string), which will give you data you can pass to SecCertificateCreateWithData. See: #10580485Sergo
S
0

Here's how I did this:

let cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)?.takeRetainedValue()

if cert != nil {
    var trust: Unmanaged<SecTrust>?

    let policy = SecPolicyCreateBasicX509().takeRetainedValue()
    let status = SecTrustCreateWithCertificates(cert, policy, &trust)

    if status == errSecSuccess {
        let trustRef = trust!.takeRetainedValue()
        let key = SecTrustCopyPublicKey(trustRef)!.takeRetainedValue();
    }
}

This works, but you need to make sure that what you pass to SecCertificateCreateWithData() is a DER-encoded certificate, and not just a DER-encoded key. You need a certificate signed by your server's private key to the get the associated public key.

Subjunctive answered 26/4, 2015 at 21:48 Comment(0)
C
0

I Did this used Alamofire:

private static func publicKeyForCertificate(certificate: SecCertificate) -> SecKey? {
    var publicKey: SecKey?
    var trust: Unmanaged<SecTrust>?

    let policy = SecPolicyCreateBasicX509().takeRetainedValue()
    let status = SecTrustCreateWithCertificates(certificate, policy, &trust)

    if status == errSecSuccess {
        let trustRef = trust!.takeRetainedValue()
        publicKey = SecTrustCopyPublicKey(trustRef)!.takeRetainedValue()

    }
    return publicKey

}
Cuboid answered 5/8, 2015 at 7:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.