在 Swift 中使用 SecRandomCopyBytes

Posted

技术标签:

【中文标题】在 Swift 中使用 SecRandomCopyBytes【英文标题】:Using SecRandomCopyBytes in Swift 【发布时间】:2017-02-10 17:57:58 【问题描述】:

我想在 Swift 3.0 中使用 SecRandomCopyBytes 生成随机字节。这是我在 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
    

在 Swift 3 中,我尝试这样做,因为我知道 unsafemutablebytes 的概念现在不同了,但它不允许我返回。如果我注释掉返回部分,它仍然会显示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

有谁知道如何解决这个问题?

谢谢

【问题讨论】:

【参考方案1】:

你很接近,但 return 在闭包内返回 来自闭包,而不是来自外部函数。 因此只有SecRandomCopyBytes() 应该在 关闭,并将结果传回。

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
    

对于“单表达式闭包”,可以推断出闭包类型 自动,因此可以缩短为

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 更新:

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
    

【讨论】:

@CodeOverRide:感谢您修复“重叠访问”问题。我已经简化了一点,不需要复制数据。在闭包内不使用keyData.count 就足够了。 是的,刚刚发现不需要了。 这在 Swift 5 中不再有效,因为现在 withUnsafeMutableBytes 公开了 UnsafeMutableRawBufferPointer 而不是 UnsafeMutablePointer @MartinR,我们可以在arc4random_uniform(&lt;num&gt;)SecRandomCopyBytes 这样的范围内生成一个随机数吗? @AnkitJayaswal:不是开箱即用,但实现起来并不难(类似于***.com/a/26550169/1187415)。但请注意,从 Swift 4.2 开始,Swift 标准库提供了一个随机数生成器,根据developer.apple.com/documentation/swift/…,它在密码学上是安全的。【参考方案2】:

这是使用 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()

当函数的控制流取决于表达式的成功或失败或非 nil 值的存在时,通常在 Swift 中使用保护语句而不是 if/else 语句是最佳实践。

【讨论】:

【参考方案3】:

根据Apple Documentation,它看起来类似于:

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

或作为额外的初始化器:

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
        
    

【讨论】:

以上是关于在 Swift 中使用 SecRandomCopyBytes的主要内容,如果未能解决你的问题,请参考以下文章

swift 优雅地处理Swift中可本地化的字符串。注意:此代码在Swift 2中,需要在现代Swift中使用更新。

在 Swift 项目中使用 Objective C 类中的 Swift 类

在 Swift 项目中使用 Objective C 类中的 Swift 类

如何在 Swift 中使用 Apple 地图 - 你必须使用 C 还是 Swift 可以?

swift 在swift中使用javascriptcore

swift 在swift中使用枚举练习