在 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(<num>)
和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 类