Using SecRandomCopyBytes in Swift

I want to generate random bytes using SecRandomCopyBytes in Swift 3.0. This is how I did it in Swift 2.2

 private static func generateRandomBytes() -> String? { let data = NSMutableData(length: Int(32)) let result = SecRandomCopyBytes(kSecRandomDefault, 32, UnsafeMutablePointer<UInt8>(data!.mutableBytes)) if result == errSecSuccess { return data!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)) } else { print("Problem generating random bytes") return nil } } 

In Swift 3, I tried to do it this way, since I know that the concept of unsafemutablebytes is different now, but that does not allow me to return. If I comment on the returned part, it still says Generic Parameter ResultType could not be inferred

 fileprivate static func generateRandomBytes() -> String? { var keyData = Data(count: 32) _ = keyData.withUnsafeMutableBytes {mutableBytes in let result = SecRandomCopyBytes(kSecRandomDefault, keyData.count, mutableBytes) if result == errSecSuccess { return keyData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)) } else { print("Problem generating random bytes") return nil } } return nil } 

Does anyone know how to fix this?

thanks

+9
source share
2 answers

You were close, but return inside the closure returns from the closure, not from an external function. Therefore, only SecRandomCopyBytes() should be called in the closure, 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 β€œone-expression closure”, the closure type can be inferred automatically, so it can be reduced 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 } } 
+23
source

According to Apple documentation, it looks something like 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 } } } 
+3
source

All Articles