【问题标题】:Random unique string generation to use as nonce (oauth)随机唯一字符串生成用作 nonce (oauth)
【发布时间】:2014-09-09 23:32:33
【问题描述】:

我正在尝试使用 UUID 生成随机数以用于 Twitter 反向身份验证。但显然 UUID 不是一个好的选择。那么,如何在每次剥离所有非单词字符时生成一个唯一的随机字符串,并注意它在使用后从内存中释放。以下代码崩溃。

    var uuid: CFUUIDRef = CFUUIDCreate(nil)
    var nonce: CFStringRef = CFUUIDCreateString(nil, uuid)
    CFRelease(uuid)

    println("createdNonce:\(nonce)")

编辑: 我在 xcode6 beta2 上,我无法调试,并且 xocde 崩溃,任何机会。好吧,CFRelease 部分对我来说是崩溃的。一旦我删除,它似乎工作正常,但我不知道这是否会造成内存泄漏。

至于为什么 UUID 可能不是用于 nonce 的好选择,似乎是因为 UUID 不是由真正的随机位组成的,请在此处参考此讨论:https://github.com/aws/aws-sdk-ios/issues/30

【问题讨论】:

  • 看看NSUUID,它是ObjC,因此更适合Swift。为什么不直接为 nonce 生成一个随机字符串?
  • 你能解释一下为什么你认为 UUID 是一个糟糕的选择吗?这段代码在 Swift 操场上对我来说很好用。您能否分享有关崩溃的更多详细信息?
  • 添加信息@AaronGolden
  • @srinivas 参考我关于崩溃的回答
  • @srinivas UUID v4(我假设 CFUUID 使用,v4 是随机的)在 128 个中提供 122 个随机位。根据您的需要,这可能就足够了。当然,假设您不将其序列化为十六进制。

标签: ios swift nonce


【解决方案1】:

更正确的生成 nonce 的方法可能是使用加密 RNG 生成随机字节。 iOS恰好有这样的东西:

var s = NSMutableData(length: 32)
SecRandomCopyBytes(kSecRandomDefault, UInt(s.length), UnsafePointer<UInt8>(s.mutableBytes))

// s is now a NSData containing 32 random bytes

然后使用 API 建议的任何格式(可能是 Base64)转换为字符串,例如

let base64str = s.base64EncodedStringWithOptions(0)

编辑:上面的方法似乎是 Twitter 在文档中使用的方法。见here。我不能说 UUIDS 是否更容易预测。这取决于它们的生成方法。不过,SecRandomCopyBytes 似乎用于加密目的,因此使用起来应该是安全的。

【讨论】:

  • 在 Swift 中发生了很多变化。现在看起来更像这样:SecRandomCopyBytes(kSecRandomDefault, s!.length, UnsafeMutablePointer&lt;UInt8&gt;(s!.mutableBytes))let base64String = s!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(0))
【解决方案2】:

Firebase's Authenticating Using Apple tutorial提供的一个例子:

// Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
private func randomNonceString(length: Int = 32) -> String {
  precondition(length > 0)
  let charset: Array<Character> =
      Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
  var result = ""
  var remainingLength = length

  while remainingLength > 0 {
    let randoms: [UInt8] = (0 ..< 16).map { _ in
      var random: UInt8 = 0
      let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
      if errorCode != errSecSuccess {
        fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
      }
      return random
    }

    randoms.forEach { random in
      if remainingLength == 0 {
        return
      }

      if random < charset.count {
        result.append(charset[Int(random)])
        remainingLength -= 1
      }
    }
  }

  return result
}

【讨论】:

    【解决方案3】:

    您的代码正在崩溃,因为您正在调用CFRelease。在swift 中,无需调用CFRelease。来自swift guide

    从带注释的 API 返回的 Core Foundation 对象会自动 Swift 中管理的内存——你不需要调用 CFRetain, CFRelease 或 CFAutorelease 函数自己。

        var uuid: CFUUIDRef = CFUUIDCreate(nil)
        var nonce: CFStringRef = CFUUIDCreateString(nil, uuid)
       //Remove this swift will manage the memory managment.This line is causing crash  
       //CFRelease(uuid) 
        println("createdNonce:\(nonce)")
    

    这段代码可以正常工作。不,这不会造成内存泄漏,Swift 会解决这个问题

    【讨论】:

    • 完全错过了 Swift 自动管理 CF 对象。另一个推动 Swift 的理由 :) +1
    【解决方案4】:

    使用 SwiftUI 5.x 和 CryptoKit,这很容易:

    import CryptoKit
    
    let nonce = ChaChaPoly.Nonce.init()
    

    使用中:

    let encryptedContent = try! ChaChaPoly.seal(inputBuffer, using: symmetricKey, nonce: ChaChaPoly.Nonce.init()).combined
    

    【讨论】:

    • 有没有办法只得到一个随机数字符串?
    • @Zorayr 简单字符串Data(ChaChaPoly.Nonce()).base64EncodedString()
    • 有什么方法可以控制生成的随机数的长度?
    【解决方案5】:

    这是一个适用于 Swift 4 的答案:

    func generateNonce(lenght: Int) throws -> Data {
        let nonce = NSMutableData(length: lenght)
        let result = SecRandomCopyBytes(kSecRandomDefault, nonce!.length, nonce!.mutableBytes)
        if result == errSecSuccess {
            return nonce! as Data
        } else {
            throw Error
        }
    }
    

    【讨论】:

      【解决方案6】:

      这可能不是一个完美的解决方案,但想提出建议,因为这将花费你大量的 Twitter 反向身份验证。

      尝试使用 cocoapod TWReverseAuth

      【讨论】:

      • 我之前做错了。现在,我在服务器上生成 x_reverse_auth 令牌并由移动客户端调用,然后使用 SLRequest 向 twitter 进行身份验证。我扩展了 j7mbo/twitter-php-app 来做 twitter 反向认证。这是库:github.com/srinivasmangipudi/twitter-api-php
      【解决方案7】:

      这是一个更简单的方法:

          var temp = NSUUID.UUID().UUIDString
          var nonce = temp.stringByReplacingOccurrencesOfString("-", withString: "")
          println("createdNonce:\(nonce)")
      

      【讨论】:

        猜你喜欢
        • 2012-11-21
        • 2010-10-18
        • 1970-01-01
        • 1970-01-01
        • 2011-08-18
        • 2017-02-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多