Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate an RSA asymmetric Key Pair in Swift for IOS?

I need a way to generate an RSA asymmetrical key pair in Swift. I don't need to store it in the keychain or anything. I just need to generate a key pair and shove both keys into String variables.

The keys do need to be compatible with PHP on the other end. I will use symmetrical encryption to secure the private key and store it on the phone. I'll be sending the public key to a web service that is implemented in PHP, and the web service will store the public key in a database.

That public key will be used later by the web service to encrypt values like one-time passwords and other sensitive values destined for the IOS app. I'll implement a similar scheme for small pieces of data flowing from the IOS app to the web service.

The only documented API declaration I could find for generating a key pair in Swift is shown on developer.apple.com:

func SecKeyGeneratePairAsync(_ parameters: CFDictionary!,
                           _ deliveryQueue: dispatch_queue_t!,
                           _ result: SecKeyGeneratePairBlock!)

I tried to figure out how to use this, but XCode doesn't like the underscores, and I'm not sure what I am actually supposed to do with this or how to use it.

Even if XCode would accept it, I am not sure how I would call the function and what values to pass it, etc. I included "import Security" at the top, so that's not the problem.

It's ridiculous that this should be so hard. All I want to do is generate an asymmetric key pair.

It's a piece of cake to do this in PHP or .NET or Java or any other language, but I can't find any clear documentation on it for Swift. I have to use Swift for this app. I don't want to use OpenSSL because it's deprecated.

I am using Swift because I bloody hate objective C. Swift is the reason I am finally jumping into IOS development.

I don't know how to integrate an Objective C class with Swift, and I'd really rather have a pure Swift solution if there is one. If not, I'd appreciate some pointers on how to integrate an Objective C solution and make it work.

The above snippet is the only function call Apple provides, and naturally it's incomplete, doesn't make sense, and doesn't work.

like image 297
C Landreaux Avatar asked Mar 03 '15 20:03

C Landreaux


People also ask

How do I create a RSA key pair?

To generate a key pair, select the bit length of your key pair and click Generate key pair. Depending on length, your browser may take a long time to generate the key pair. A 1024-bit key will usually be ready instantly, while a 4096-bit key may take up to several minutes.

How do you make an asymmetric key pair?

For instance, asymmetric encryption consists of a triple Gen , Enc and Dec where Gen represents the key pair generation. And the key pair of course consists of a public and a private part. RSA basically starts off by generating two large random primes, it doesn't start with a single number necessarily.


2 Answers

There is a good example of how to do this in Swift in the CertificateSigningRequestSwift_Test project in GitHub. Using a single call to SecKeyCreateRandomKey() one can generate the public/private key pair both at the same time and they will be saved in the keychain.

        let tagPublic = "com.example.public"
        let tagPrivate = "com.example.private"

        let publicKeyParameters: [String: AnyObject] = [
            String(kSecAttrIsPermanent): kCFBooleanTrue,
            String(kSecAttrApplicationTag): tagPublic as AnyObject,
            String(kSecAttrAccessible): kSecAttrAccessibleAlways
        ]

        var privateKeyParameters: [String: AnyObject] = [
            String(kSecAttrIsPermanent): kCFBooleanTrue,
            String(kSecAttrApplicationTag): tagPrivate as AnyObject,
            String(kSecAttrAccessible): kSecAttrAccessibleAlways
        ]

        //Define what type of keys to be generated here
        var parameters: [String: AnyObject] = [
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecAttrKeySizeInBits): 2048,
            String(kSecReturnRef): kCFBooleanTrue,
            kSecPublicKeyAttrs as String: publicKeyParameters as AnyObject,
            kSecPrivateKeyAttrs as String: privateKeyParameters as AnyObject,
        ]

        //Use Apple Security Framework to generate keys, save them to application keychain
        var error: Unmanaged<CFError>?
        let privateKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error)

        if privateKey == nil{
            print("Error creating keys occurred: \(error!.takeRetainedValue() as Error), keys weren't created")
            return
        }

        //Get generated public key
        let query: [String: AnyObject] = [
            String(kSecClass): kSecClassKey,
            String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag): tagPublic as AnyObject,
            String(kSecReturnRef): kCFBooleanTrue
        ]

        var publicKeyReturn:AnyObject?

        let result = SecItemCopyMatching(query as CFDictionary, &publicKeyReturn)

        if result != errSecSuccess{
            print("Error getting publicKey from keychain occurred: \(result)")
            return
        }

        let publicKey = publicKeyReturn as! SecKey?

        //Set block size
        let keyBlockSize = SecKeyGetBlockSize(self.publicKey!)

        //Ask keychain to provide the publicKey in bits
        let query: [String: AnyObject] = [
            String(kSecClass): kSecClassKey,
            String(kSecAttrKeyType): keyAlgorithm.secKeyAttrType,
            String(kSecAttrApplicationTag): tagPublic as AnyObject,
            String(kSecReturnData): kCFBooleanTrue
        ]

        var tempPublicKeyBits:AnyObject?

        _ = SecItemCopyMatching(query as CFDictionary, &tempPublicKeyBits)

        guard let publicKeyBits = tempPublicKeyBits as? Data else {
            return
        }
like image 102
mbonness Avatar answered Oct 23 '22 10:10

mbonness


Heimdall seems to be what you're looking for. It's easy to use, can create RSA keypairs, encrypt, decrypt, sign and verify.

It uses the iOS/OS X keychain for storing the keys, so the keys are stored in a secure way.

From the GitHub Readme:

if let heimdall = Heimdall(tagPrefix: "com.example") {
    let testString = "This is a test string"

    // Encryption/Decryption
    if let encryptedString = heimdall.encrypt(testString) {
        println(encryptedString) // "cQzaQCQLhAWqkDyPoHnPrpsVh..."

        if let decryptedString = heimdall.decrypt(encryptedString) {
            println(decryptedString) // "This is a test string"
        }
    }

    // Signatures/Verification
    if let signature = heimdall.sign(testString) {
        println(signature) // "fMVOFj6SQ7h+cZTEXZxkpgaDsMrki..."
        var verified = heimdall.verify(testString, signatureBase64: signature)
        println(verified) // True

        // If someone meddles with the message and the signature becomes invalid
        verified = heimdall.verify(testString + "injected false message",
                                    signatureBase64: signature)
        println(verified) // False
    }
}
like image 41
vrwim Avatar answered Oct 23 '22 09:10

vrwim