SecRandomCopyBytes, or: Playing Unsafe with Swift

21st March, 2015 — Stefan van den Oord

The Apple Security Framework has this function SecRandomCopyBytes() that allows you to create an array of cryptographically secure random bytes. There are many ways to generate random data on iOS and OS X, but I wanted to use this one because it is suitable for cryptographic purposes. Of course I could have used arc4random(), but then this blog post would not have been nearly as interesting. So SecRandomCopyBytes() it is. Now, this project that I'm working on happens to be written in Swift. And I didn't have a clue how to call it from Swift. So let's start the easy way.

Round 1: Objective-C

What I do know, is how to call it from Objective-C.

Objective-C:int32_t randomNumber = 0;
SecRandomCopyBytes(kSecRandomDefault, 4, (uint8_t*) &randomNumber);

That wasn't so hard. First, we declare a 32-bit integer (and initialize it to zero). Then we call SecRandomCopyBytes passing 4 as count (4 bytes are 32 bits), as well as the memory location where the random bytes should be stored: the address of the random number integer that we just declared. Success, we won round 1.

Round 2: First Swift Attempt

I guess I could wrap it up here, after all it's no problem at all to call Objective-C from Swift. But that's cheating, what would I have learned? So let's try this in Swift.

Swift:var randomNumber : Int32  = 0
SecRandomCopyBytes(kSecRandomDefault, 4, &randomNumber)

Unfortunately, this results in a compiler error: 'Int32' is not identical to 'UInt8'. The beauty of strongly typed languages! We lost this round.

Round 3: Playing Unsafe

So if this is a strongly typed language, what type is it that we need then? Looking at the documentation tells us that we need a variable of type UnsafeMutablePointer<UInt8>. So how do we take an Int32 and use it as an UnsafeMutablePointer<UInt8>? In fact, there's two steps to this: (1) obtain an UnsafeMutablePointer, and (2) cast it from a pointer to UInt32 to a pointer to UInt8.

withUnsafeMutablePointer

It turns out that we need to use withUnsafeMutablePointer for the first step. When trying to find out how this works, the Swift iBooks are of no use; it is not documented there. So let's look at the definition in Xcode. We read:

Swift:/// Invokes `body` with an `UnsafeMutablePointer` to `arg` and returns the
/// result. Useful for calling Objective-C APIs that take "in/out"
/// parameters (and default-constructible "out" parameters) by pointer
func withUnsafeMutablePointer<T, Result>(inout arg: T, body: (UnsafeMutablePointer<T>) -> Result) -> Result

Let's analyze this. withUnsafeMutablePointer is a template method that uses two template types: T and Result. It has two arguments: the first one is an in-out parameter called arg, which has type T. The second one is a closure called body. This closure takes one argument, of type UnsafeMutablePointer<T>, and has return type Result. Finally, the return type of withUnsafeMutablePointer itself is also Result.

Right. But what does it do? After reading it a couple of times, you'll find that the documentation actually says it accurately (though tersely): it takes a reference to a Swift variable, and makes it available as an UnsafeMutablePointer inside the closure. So now we can type something like this:

Swift:var randomNumber : Int32  = 0
withUnsafeMutablePointer(&randomNumber, { (randomNumberPointer) -> Void in
    var proof : UnsafeMutablePointer<Int32> = randomNumberPointer
})

This compiles, just to prove to you that the randomNumberPointer is indeed an UnsafeMutablePointer<Int32>.

unsafeBitCast

So now we get to the second step: we don't need a pointer to Int32, we need a pointer to UInt8 in order to call SecRandomCopyBytes. Enter unsafeBitCast.

As an Objective-C programmer, you probably know that the pointer is just the address of a memory location and you don't really care about the type of the pointer, as long as the size of the memory location is correct. So in Objective-C you can just use type casting:

Swift: int32_t number = 0;
 uint8_t *numberPointer = (uint8_t*) &number;

In fact, if you leave out the type cast, the compiler will only generate a warning and let you run the program anyway. The type cast is there so that we can tell the compiler that we know better than it does, it doesn't need to worry, we know what we're doing.

The function unsafeBitCast is the Swift equivalent of the type cast. Let's look at the definition:

Swift:/// Returns the the bits of `x`, interpreted as having type `U`.
///
/// .. Caution:: Breaks the guarantees of Swift's type system; use
///    with extreme care.  There's almost always a better way to do
///    anything.
///
func unsafeBitCast<T, U>(x: T, _: U.Type) -> U

So it takes a parameter x of type T and an anonymous parameter that is itself a type, and returns the parameter x casted to that type. Let's apply this to our code. We don't need to return a value from withUnsafeMutablePointer, so as a result type I choose Void. Please note the construct UnsafeMutablePointer<UInt8>.self to specify the type to which we want the pointer to be casted.

Swift:var randomNumber : Int32  = 0
withUnsafeMutablePointer(&randomNumber, { (randomNumberPointer) -> Void in
    var castedPointer = unsafeBitCast(randomNumberPointer, UnsafeMutablePointer<UInt8>.self)
    SecRandomCopyBytes(kSecRandomDefault, 4, castedPointer)
})

That's it. Now randomNumber contains 32 bits of random data. Hurrah!

Wrapping it up

I hope you learned something here, I know I did! I enjoy coding in Swift, and I am happy that Apple has the courage to keep improving it. When you get to the boundaries between Swift and (Objective-)C, it can be a struggle sometimes however.

On a final note: After reading the caution about unsafeBitCast ("There's almost always a better way to do anything") I do have this nagging question whether there is a better way in this case, and what it would be, but that's maybe for another time. Suggestions and feedback are highly appreciated! Please visit the copy of my article on Medium to leave comments.