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 :)

Community
  • 1
  • 1
jamil
  • 352
  • 1
  • 3
  • 12

3 Answers3

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.

Community
  • 1
  • 1
Antzi
  • 12,831
  • 7
  • 48
  • 74
  • An explanation of `pubKey` would make the answer much more useful. – zaph Dec 08 '15 at 13:52
  • @zaph 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... – Antzi Dec 08 '15 at 14:51
  • Thanks for adding the information, it really helps the answer. – zaph Dec 08 '15 at 15:30
  • **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.der` – Husam Mar 31 '17 at 07:40
  • 1
    Does that mean we must use der file only, cannot use pem key in iOS? – DàChún Feb 12 '18 at 10:32
  • 12
    This doesn't answer the question 'SecKey from public key string sent from the server' – Sameer Bhide Mar 22 '18 at 04:43
  • 1
    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: https://stackoverflow.com/questions/10579985/how-can-i-get-seckeyref-from-der-pem-file – Koen. Dec 29 '20 at 18:05
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.

hrunting
  • 3,857
  • 25
  • 23
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

}
Antzi
  • 12,831
  • 7
  • 48
  • 74
Zeus
  • 128
  • 1
  • 11