Using CommonCrypto in Swift

Using CommonCrypto in Swift is tricky because it is not a standalone module, so you cannot just {swift}import CommonCrypto{/swift}. In this post I will describe three methods that facilitate using {default}CommonCrypto{/default} in Swift and how to choose which method is best for your situation.

Bridging Header

If you simply want to call CommonCrypto routines from your own app, the easiest solution is to add a bridging header to your project and {objc}#import {/objc} in that header.

If your app is not a mixed source app and you do not already have a bridging header the easiest way to create one is to add a new Objective-C class to your project. Xcode will show an action sheet asking if you want to create one. Once the header is created you can delete the dummy Objective-C class from your project.

You can also add a bridging header manually, but it is a little more tedious. To do this, create a header file and then go to Build Settings and in the section Swift Compiler – Code Generation set the Objective-C Bridging Header to point to the file you just created.

You do not need to {objc}import CommonCrypto{/objc} in your Swift source when using a bridging header.

Local Module Map

Bridging headers work fine for apps, but if you are trying to build a framework to wrap {default}CommonCrypto{/default} you cannot use this approach; Xcode does not allow the use of bridging headers in framework targets.

To work around this create a directory called {default}CommonCrypto{/default} somewhere. In this directory create a file name {default}module.map{/default} and copy the following into the file. You will need to alter the paths to ensure they point to the headers on your system.
[default]
module CommonCrypto [system] {
header “/Applications/Xcode-6.0.1-6A317.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.sdk/usr/include/CommonCrypto/CommonCrypto.h”
header “/Applications/Xcode-6.0.1-6A317.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.sdk/usr/include/CommonCrypto/CommonRandom.h”
export *
}
[/default]

To make this module visible to Xcode, go to Build Settings, Swift Compiler – Search Paths and set Import Paths to point to the directory that contains the {default}CommonCrypto{/default} directory.

You should now be able to use {swift}import CommonCrypto{/swift} in your Swift code.

You have to set the Import Paths in every project that uses your framework so that Xcode can find it.

Global Fake Module

Swift playgrounds are great for experimenting with code and learning how to use APIs, unfortunately, neither of the above methods make CommonCrypto available in a playground.

The only way I’ve found to work around this is to create a fake {default}CommonCrypto.framework{/default} down in the SDK directory where playgrounds look for their files.

To this, open a terminal window and change into the simulator’s {default}Frameworks{/default} directory. The easiest way to do this is to use the following command:
[default]
cd `xcrun -sdk iphonesimulator8.0 -show-sdk-path`/System/Library/Frameworks
[/default]

Create a directory named {default}CommonCrypto.framework{/default} containing the {default}module.map{/default} file from the previous section.

You should now be able to create a playground and {swift}import CommonCrypto{/swift}.

If you use this method, {default}CommonCrypto{/default} will be available to all apps, framework and playgrounds, although it does “pollute” the SDK as one developer pointed out to me. Notwithstanding this, until an official method emerges, this is the only way!

Calling into CommonCryto

Whichever method you choose to make CommonCrypto available, you will still need to figure out how to call the API from Swift. To say that code to do this is inelegant would be quite an understatement.

The example below shows how to use {default}CommonCrypto{/default} to compute an MD5 message digest.

var s = "The quick brown fox jumps over the lazy dog."
var context = UnsafeMutablePointer<CC_MD5_CTX>.alloc(1)
var digest = Array<UInt8>(count:Int(CC_MD5_DIGEST_LENGTH), repeatedValue:0)
CC_MD5_Init(context)
CC_MD5_Update(context, s, 
        CC_LONG(s.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)))
CC_MD5_Final(&digest, context)
context.dealloc(1)
var hexString = ""
for byte in digest {
    hexString += String(format:"%02x", byte)
}
println(hexString)

I am working on a framework to make this all much easier, but it is not ready for primetime just yet. You can find it on Github in the IDZSwiftCommonCrypto repository.

Conclusion

The methods presented here have been tested with Xcode 6.0.1 (6A317), changes to Xcode may break them!

If you want to ship a framework using {default}CommonCrypto{/default} your clients will beed to use either method 2 or 3 to ensure correct linking.


About idz

A professional software engineer dabbling in iOS app development.
This entry was posted in Objective-C, Swift, Tutorial. Bookmark the permalink.

6 Responses to Using CommonCrypto in Swift

  1. mikewogden says:

    Any ideas why I cannot compile this in XCode Version 6.2 (6C131e)? I get 1 error and 1 warning:
    Error: Swift Compile Error. Could not build Objective-C module ‘CommonCrypto’
    Warning: Dependency Analysis Warning. Warning: no rule to process file ‘…/IDZSwiftCommonCrypto/README.md’ of type net.daringfireball.markdown for architecture x86_64
    thank you.

  2. mikewogden says:

    looks like I figured it out. the module.map was not referencing my xcode and sdk path locations properly.

    module CommonCrypto [system] {
    header “/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.2.sdk/usr/include/CommonCrypto/CommonCrypto.h”
    header “/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.2.sdk/usr/include/CommonCrypto/CommonRandom.h”
    export *
    }

  3. Pingback: How to convert string to MD5 hash using ios swift - BlogoSfera

  4. Wendy says:

    Is there any method to write a relative path of header since the Xcode.app path is not sure?

  5. Pingback: How to use CC_MD5 method in swift language. - ExceptionsHub

  6. Pingback: How to hash a string to SHA512 in Swift? – inneka.com

Leave a Reply