Using SecRandomCopyBytes in Swift Using SecRandomCopyBytes in Swift swift swift

Using SecRandomCopyBytes in Swift


You were close, but return inside the closure returnsfrom the closure, not from the outer function.Therefore only SecRandomCopyBytes() should be called in theclosure, and the result passed back.

func generateRandomBytes() -> String? {    var keyData = Data(count: 32)    let result = keyData.withUnsafeMutableBytes {        (mutableBytes: UnsafeMutablePointer<UInt8>) -> Int32 in        SecRandomCopyBytes(kSecRandomDefault, 32, mutableBytes)    }    if result == errSecSuccess {        return keyData.base64EncodedString()    } else {        print("Problem generating random bytes")        return nil    }}

For a "single-expression closure" the closure type can inferredautomatically, so this can be shortened to

func generateRandomBytes() -> String? {    var keyData = Data(count: 32)    let result = keyData.withUnsafeMutableBytes {        SecRandomCopyBytes(kSecRandomDefault, 32, $0)    }    if result == errSecSuccess {        return keyData.base64EncodedString()    } else {        print("Problem generating random bytes")        return nil    }}

Swift 5 update:

func generateRandomBytes() -> String? {    var keyData = Data(count: 32)    let result = keyData.withUnsafeMutableBytes {        SecRandomCopyBytes(kSecRandomDefault, 32, $0.baseAddress!)    }    if result == errSecSuccess {        return keyData.base64EncodedString()    } else {        print("Problem generating random bytes")        return nil    }}


This is the simplest and "Swiftiest" way to implement your function using Swift 5:

func generateRandomBytes() -> String? {    var bytes = [UInt8](repeating: 0, count: 32)    let result = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)    guard result == errSecSuccess else {        print("Problem generating random bytes")        return nil    }    return Data(bytes).base64EncodedString()}

Generally it is best practice in Swift to use guard statements as opposed to if/else statements when the control flow of a function depends on the success or failure of an expression or the presence of a non-nil value.


According to Apple Documentation it looks similar to this:

public func randomData(ofLength length: Int) throws -> Data {    var bytes = [UInt8](repeating: 0, count: length)    let status = SecRandomCopyBytes(kSecRandomDefault, length, &bytes)    if status == errSecSuccess {        return Data(bytes: bytes)    }    // throw an error}

or as an additional initializer:

public extension Data {    public init(randomOfLength length: Int) throws {        var bytes = [UInt8](repeating: 0, count: length)        let status = SecRandomCopyBytes(kSecRandomDefault, length, &bytes)        if status == errSecSuccess {            self.init(bytes: bytes)        } else {            // throw an error        }    }}